Similarities and differences between C and Java
I have had a wrong point of view: even if the implementation mechanism in C and Java may be different, their performance form should be the same, that is, if the code structure is the same, the execution result should also be the same. Unfortunately, things are not like this. (In view of the following, you should first consider this problem, what do you think?)
OK, let us enter the topic.
First, this article does not discuss object-oriented programming, such as encapsulation, inheritance, and data abstraction, this area should now be much like a buff, just a slight concept. According to Bjarne Stoustrup, the polymorphism is actually the mechanism of method calls, that is, when the actual type of object is not determined at compile, it should be able to determine the specific method of the call based on the actual type of object at runtime (dynamic Bind).
Let's first look at the function call mode in C :
Ø Normal function call: which method of the specific call can be decided in compiling time (by looking for symbolic tables of the compiler), while adding a pointer (THIS pointer) representing an object identity on the basis of the standard process call mechanism.
Ø Virtual function call: Function call relies on the actual type of object, in general, the actual type of object can only be determined at runtime. The virtual function generally has two steps to support. First, each class generates a plug that points to the virtual function, placed in the table, this table is called virtual table; then each class object (Class Object) ) Add a pointer to the relevant virtual table (Virtual Table), usually this pointer is called VPTR.
What is it in Java? Well, the difference is still full. In the Java virtual machine, the reference to the class instance is a pointer to a handle, and the handle is actually a pair of pointers: one of the pointers points to a table, the table contains the object's method list and one Pointer to the key object (indicated object type); another pointer points to a memory address, which is assigned from the data of the object from the Java heap.
Hey, you have to say, it seems to be almost, don't you maintain a function table? Don't worry, let's take a look at the example, so that you can better understand how big it is in the end.
Here are examples of C and Java, don't look at the back of the answer, can you correctly say their execution results?
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 deerid ();
}
}
Example 1 execution result is:
In base :: init ()
In Derived :: init ()
Example 2's execution result is:
In Derived :: init ()
In Derived :: init ()
After watching the results, are you soon to have a doubt? OK, let's analyze the execution of two examples.
First take a look at the example 1 (C example):
1. Base * Pb; just statement, don't do anything.
2. Pb = new deerived ();
1) Call the New operator to allocate memory.
2) Call the constructor of the base class (this example is BASE)
3) Calling init () in the construction function of the base class, the executor first judges that the actual type of the current object is BASE (Derived has not been constructed, and of course it will not be derived), so this is called Base :: init ( ).
4) Call the constructor of the derived class (this example is Derived), here is the init (), the executor determines that the actual type of the current object is Derived, call Derived :: init ().
3. Delete PB; None of the critical.
Example 2 (Example of Java):
1. Base base = new derived ();
1) Distribute memory.
2) Call the constructor of the base class (this example is BASE)
3) Calling init () in the constructor of the base class, the execution program first determines that the actual type of the current object is Derived (pair, Derive has been configured, its function table is of course confirmed), so it is called Derived :: INIT ().
4) Call the constructor of the derived class (this example is Derived), here is the init (), the executor determines that the actual type of the current object is Derived, call Derived :: init ().
you got it. The class object in Java has existed prior to constructing (before calling constructor), its function table and object type have also been determined, that is, there is already no birth. Only C only exists after the construction is completed (all constructor is successful), the actual type of the function table and the object is determined. So the execution results of these two examples are different. Of course, after the configuration is completed, C is the same as the Java performance, for example, if you call Derived :: Do_init (), its execution result is: in derived :: init ().
Personally, the polymorphism implementation mechanism in Java is not good in C . Or explain as an example:
Example 3: C
Class Base
{
PUBLIC:
Base ()
{
INIT ();
}
Virtual ~ base () {}
protected:
Int value;
Virtual void init ()
{
Value = 100;
}
}
Class Derived: Public Base
{
PUBLIC:
Derived ()
{
INIT ();
}
protected:
void init ()
{
COUT << "value =" << value << endl;
/ / Do 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 ()
{
Value = 100;
}
}
Class Derived Extends Base
{
Public derived ()
{
INIT ();
}
protected void init ()
{
System.out.println ("Value =" Value);
/ / Do some extra initialization work
}
}
Public Class Test
{
Public static void main (string [] args)
{
Base base = new deerid ();
}
}
Example 3 execution result is:
Value = 10
Example 4 execution result is:
Value = 0
Value = 0
As can be seen from the above results, the value of the initialized value (here is Value) in the Java example is not initialized, and the derived class cannot reuse the initialization function of the base class. Question, if initialization is completed during construction, and the initialization logic is more complicated, the derived class also needs additional initialization, is the derived class need to re-implement the initialization function of the base class? Is this object-oriented method? Welcome everyone to discuss.
Author's contact: smart_ttc@yahoo.com.cn
REFERENCE:
1. Stanley B. Lippman: Depth Exploring the C Object Model (Inside the C Object Model).
---- Houjie Translation, Huazhong Technology Press 2001
2. Bjarne Stoustrup: What is "Object-Oriented Programming" (1991 Revise Version) There is: http://www.9cbs.net/develop/read_article.asp? Id = 14303