Differences between C ++ and Java Polymorphism

Source: Internet
Author: User

In C ++, if the front side of the function in the parent class is marked with virtual, polymorphism occurs.

If the parent class func is virtual

Super * P = new sub ();

P-> func (); // call the func of the subclass.

If it is not virtual, p-> func will call the original function of the parent class.

 

In Java, no matter whether you write or not write the virtual code, the function with the same name as the subclass override parent class. Unlike C ++, the initialization process is also different. When the subclass is not initialized, the function with the same name of the subclass will overwrite the parent class. For example:

Public class super {
Public super (){
System. Out. println ("Super constructor ...");
M ();
}

Protected void M (){

System. Out. println ("test ");
}
}

 

Public class sub extends super {
Private final date;
Public sub (){

System. Out. println ("sub constructor ...");
Date = new date ();}
Public void M ()
{
System. Out. println (date );
}

Public static void main (string [] ARGs)
{
Super test1 = new sub ();

Test1.m (); // m of the execution subclass
}
}

When new sub is used, super is called first. M called by super constructor is already covered by sub, so null is printed (because the date is not initialized ). Therefore, in Java, do not call an externally changeable method in the parent class constructor. It is possible that something that has not been initialized in the changeable method will be output.

However, the same Initialization is in C ++. When initializing a subclass, the M called by the parent class is the M of the parent class and does not call the subclass.

------

Another reference is also useful: http://7880.com/info/article-51701560.html, as shown below:

C ++AndJavaSimilarities and differences between Polymorphism mechanisms in

In the past, I had a wrong idea: even though the implementation mechanisms of polymorphism in C ++ and Java may be different, they should have the same representation, that is, if the code structure is the same, the execution results should also be the same. Unfortunately, this is not the way you think. (Before reading the following, you 'd better consider this question first. What do you think ?)

OK. Let's go to the topic.

First of all, this article does not discuss the basic concepts of object-oriented programming, such as encapsulation, inheritance, and data abstraction. At present, this information should be a bit more, just to mention the concept of polymorphism. According to Bjarne stoustrup, polymorphism is actually a method call mechanism, that is, when the actual type of an object cannot be determined during compilation, you should be able to determine the calling method (dynamic binding) based on the actual object type at runtime ).

Let's take a look.In C ++Function call method:

Ø normal function call: you can determine the method to call at the compilation time (by searching the symbol table of the compiler ), at the same time, a pointer (this pointer) indicating the identity of the object is added based on the standard process call mechanism ).

Ø virtual function call: function call depends on the actual type of the object. Generally, the actual type of the object can only be determined during running time. There are two steps to support virtual functions. First, each class generates a bunch of pointers pointing to the virtual function and puts them in the table. This table is called a virtual table ); then, each class object will add a pointer to the virtual table. Generally, this pointer is called vptr.

InJavaHow is it? Well, the difference is big. In a Java virtual machine, a reference to a class instance is a pointer to a handle, which is actually a pair of pointers: one pointer points to a table, this table contains a list of object methods and a pointer to a Class Object (Object Type). The other Pointer Points to a memory address, the memory is allocated from the Java heap for object data.

Well, you have to say, it seems like, isn't it necessary to maintain a function table? Don't worry. Let's take a look at the example first so that you can better understand the differences between them.

The following is an example of C ++ and Java. Can you correctly explain the execution results without looking at the following answers?

Example 1: C ++

Class base

{

Public:

Base ()

{

Init ();

}

Virtual ~ Base (){}

Public:

Virtual void do_init ()

{

Init ();

}

Protected:

Virtual void Init ()

{

Cout <"in base: Init ()" <Endl;

}

};

Class derived: public Base

{

Public:

Derived ()

{

Init ();

}

Protected:

Void Init ()

{

Cout <"in derived: Init ()" <Endl;

}

};

Int main (INT argc, char * argv [])

{

Base * pb;

PB = new derived ();

Delete Pb;

Return 0;

}

Example 2: Java

Class base

{

Public base ()

{

Init ();

}

Protected void Init ()

{

System. Out. println ("in base: Init ()");

}

Public void do_init ()

{

Init ();

}

}

Class derived extends Base

{

Public derived ()

{

Init ();

}

Protected void Init ()

{

System. Out. println ("in derived: Init ()");

}

}

Public class test

{

Public static void main (string [] ARGs)

{

Base base = new derived ();

}

}

The execution result of Example 1 is:

In base: Init ()

In derived: Init ()

The execution result of Example 2 is:

In derived: Init ()

In derived: Init ()

After reading the results, do you have an epiphany immediately or are you in doubt? OK. Let's analyze the execution process of the two examples.

First, let's take a look at Example 1 (C ++ example ):

1. Base * pb; only declares and does nothing.

2. Pb = new derived ();

1) call the new operator to allocate memory.

2) Call the constructor of the base class (in this example, base ).

3) Call Init () in the base class constructor. The execution program first determines that the actual type of the current object is base (derived is not constructed yet, of course, it is not derived ), so here we call base: Init ().

4) Call the constructor of the derived class (in this example, derived). In this example, call Init () and run the program to determine whether the actual object type is derived. Call derived :: init ().

3. Delete Pb; irrelevant.

Example 2 (Java example:

1. Base base = new derived ();

1) allocate memory.

2) Call the constructor of the base class (in this example, base ).

3) Call Init () in the base class constructor. The execution program first determines that the actual type of the current object is derived (pair, derived has been constructed, of course, its function table has been determined. So here we call derived: Init ().

4) Call the constructor of the derived class (in this example, derived). In this example, call Init () and run the program to determine whether the actual object type is derived. Call derived :: init ().

See. The Class Object in Java already exists before the constructor is constructed (before the constructor is called), and its function table and object type have been determined. That is to say, it already exists before it is born. In C ++, the actual types of function tables and objects are determined only after the constructor is constructed (all constructors are successfully called. Therefore, the execution results of these two examples are different. Of course, after the construction, C ++ and Java will have the same performance. For example, if you call derived: do_init (), the execution result is:

In derived: Init ().

I personally think that the implementation mechanism of polymorphism in Java is not as good as in C ++. Let's take an example:

Example 3: C ++

Class base

{

Public:

Base ()

{

Init ();

}

Virtual ~ Base (){}

Protected:

Int value;

Virtual void Init ()

{

Values = 100;

}

};

Class derived: public Base

{

Public:

Derived ()

{

Init ();

}

Protected:

Void Init ()

{

Cout <"value =" <value <Endl;

// Perform some extra initialization work

}

};

Int main (INT argc, char * argv [])

{

Base * pb;

PB = new derived ();

Delete Pb;

Return 0;

}

Example 4: Java

Class base

{

Public base ()

{

Init ();

}

Protected int value;

Protected void Init ()

{

Values = 100;

}

}

Class derived extends Base

{

Public derived ()

{

Init ();

}

Protected void Init ()

{

System. Out. println ("value =" + value );

// Perform some extra initialization work

}

}

Public class test

{

Public static void main (string [] ARGs)

{

Base base = new derived ();

}

}

The execution result of Example 3 is:

Value = 10

The execution result of Example 4 is:

Value = 0

Value = 0

From the above results, we can see that the value (here value) to be initialized in the Java example is not initialized, and the derived class cannot reuse the initialization function of the base class at all. If the initialization is completed during the construction and the initialization logic is complex, the derived classes also need additional initialization. Do the derived classes need to re-implement the initialization functions of the base classes? Is this object-oriented method good? Welcome to the discussion.

Author's contact: smart_ttc@yahoo.com.cn

Reference:

1. Stanley B. Lippman: deeply explores the C ++ Object Model (inside the C ++ object model ).

---- Hou Jie, Huazhong Science and Technology Press 2001

 

------

Another example of Java:

Http://blog.csdn.net/lzz313/archive/2009/06/16/4274936.aspx

Class Parent {

Int x = 10;
Public parent (){
Add (2 );
}
Void add (INT y ){
X + = y;
}
}

Class Child extends parent {
Int x = 9;
Void add (INT y ){
X + = y;
}
Public static void main (string [] ARGs ){
Parent P = new child ();
System. Out. println (P. X );
}
}

What is the output result?
The answer should be 10.
To understand why the result is 10, you must first understand the following knowledge:
(1) hiding and overwriting methods and variables during inheritance
Hide: If B hides a's variables or methods, B cannot access a's hidden variables or methods, however, after converting B to A, you can access the hidden variables or methods of.
Overwrite: If B overwrites the variables or methods of A, B cannot access the variables or methods covered by, after B is converted to a, the variable or method that A is overwritten cannot be accessed.
(2) hiding and overwriting rules of variables and methods in Java in inheritance:
1. instance variables and class variables of the parent class can be hidden from variables of the same name in the quilt class.
2. The static method of the parent class is hidden by the static method of the same name of the quilt class, And the instance method of the parent class is overwritten by the instance method of the same name of the quilt class.
3. You cannot use the static method of the subclass to hide the instance method of the parent class, or override the static method of the parent class with the instance method of the subclass. Otherwise, the compiler will be abnormal.
4. The final method modified with the final keyword cannot be overwritten.
5. variables can only be hidden and not overwritten. The instance variables of the subclass can hide the class variables of the parent class, and the class variables of the subclass can also hide the instance variables of the parent class.
In the above questions, the instance method add (INT y) of the Child subclass overwrites the instance method add (INT y) of the parent class ), the instance variable X of the subclass hides the instance variable X of the parent class.
The initialization process of the child object is:
First, allocate memory space for the instance variable X of the parent class. Because the value (INT x = 10) is assigned to the variable X when the variable X is defined, the value is assigned to X at the same time.
Second, the non-argument constructor of the parent class is called. The only thing that the parent constructor does is to call add (2 );
Third, because the add (INT y) method of the subclass overwrites the method of the parent class, add (2) actually calls the subclass method, in the add method of the subclass, perform the following operations x + = J. Here, because the instance variable X of the subclass hides the instance variable X of the parent class, therefore, this statement is for the subclass itself, but no space is allocated for the strength variable X of the subclass. Its default value is 0, and 2 after adding 2.
4. After the parent class is initialized, initialize the Child class, allocate memory space for X of the Child class, and assign it to 9. The previous add (2) operation is too white.
Note again that parent P = new child (); this statement points to the subclass object with reference to the parent class. As mentioned above, variables will only be hidden and not overwritten, so the p. the X value should be 10 of the parent class, rather than 9 of the Child class;
If you replace the output statement with the following statement, the result is 9:
System. Out .. println (child) P). X); // first convert P to the child Type

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.