别人问了我一个问题:若基类有一个虚函数init(),被构造函数调用,而派生类override了init(),同样在其构造函数中调用之,那么在创建一个派生类对象时,init()显然会依次被基类和派生类的构造函数调用,那么,这两次调用的分别是什么版本的init()?
我原以为按照OO的思想,在C++和Java中都应该是如下情况:构造函数中的虚函数不是真正的虚函数,而会调用当前版本的函数。
然而,测试证明我想错了,C++的结果很符合我的预期,而Java的结果让我很是觉得ugly。
在Java中,在基类的构造函数中,居然调用了派生类版本的init()。
这结果让我很困惑:难道这不是违背OO的思想么?在基类的构造函数执行过程中,这个对象的所有派生类成分都还未构建,怎么能调用派生类版本的函数呢?
翻了翻《Thinking in java 4th》,在p301发现了相关文字:
Behavior of polymorphic methods inside constructors
“if you call a dynamically bound method inside a constructor ,the overridden definition for that method is also used.However , the effect of this call be rather unexpected because the overridden method will be called before the object if fully constructed .This can conceal some
difficult-to-find bugs."
"On the other hand, you hsould be pretty horrified at the outcome of this program. You've done a perfectly logical thing,and yet the behavior is mysteriously wrong,with no complaints from the compiler. C++produces more rational behavior in this situation. Bugs like this could easily be buried and take a long time to discover."
"As a result.......The only safe methods to call inside a constructor are those that are final in the base class(This also applies to private methods,which are automatically final.)
........
Java的这个特性真是Ugly!
测试代码和结果如下
C++的
输出结果:
I am Base
I am Derived
java的
输出结果
Hello,It's Derived
Hello,It's Derived
我原以为按照OO的思想,在C++和Java中都应该是如下情况:构造函数中的虚函数不是真正的虚函数,而会调用当前版本的函数。
然而,测试证明我想错了,C++的结果很符合我的预期,而Java的结果让我很是觉得ugly。
在Java中,在基类的构造函数中,居然调用了派生类版本的init()。
这结果让我很困惑:难道这不是违背OO的思想么?在基类的构造函数执行过程中,这个对象的所有派生类成分都还未构建,怎么能调用派生类版本的函数呢?
翻了翻《Thinking in java 4th》,在p301发现了相关文字:
Behavior of polymorphic methods inside constructors
“if you call a dynamically bound method inside a constructor ,the overridden definition for that method is also used.However , the effect of this call be rather unexpected because the overridden method will be called before the object if fully constructed .This can conceal some
difficult-to-find bugs."
"On the other hand, you hsould be pretty horrified at the outcome of this program. You've done a perfectly logical thing,and yet the behavior is mysteriously wrong,with no complaints from the compiler. C++produces more rational behavior in this situation. Bugs like this could easily be buried and take a long time to discover."
"As a result.......The only safe methods to call inside a constructor are those that are final in the base class(This also applies to private methods,which are automatically final.)
........
Java的这个特性真是Ugly!
测试代码和结果如下
C++的
#include
<
iostream
>
using namespace std;
class base
{
public:
base() { init(); }
virtual void init(){ cout<<"I am Base "<<endl;}
} ;
class derived: public base
{
public:
derived() { init();}
void init() { cout<<"I am Derived "<<endl;}
} ;
int main ()
{
derived test;
return 1;
}
using namespace std;
class base
{
public:
base() { init(); }
virtual void init(){ cout<<"I am Base "<<endl;}
} ;
class derived: public base
{
public:
derived() { init();}
void init() { cout<<"I am Derived "<<endl;}
} ;
import
java.util.
*
;
class Base
{
public Base () { init(); }
private void init() { System.out.println("Hello,It'Base");}
}
class Derived extends Base
{
public Derived() { init();}
private void init() { System.out.println("Hello,It's Derived");}
}
public class Test
{
public static void main (String[] args)
{
System.out.println("in the main");
Derived d=new Derived();
}
}
class Base
{
public Base () { init(); }
private void init() { System.out.println("Hello,It'Base");}
}
class Derived extends Base
{
public Derived() { init();}
private void init() { System.out.println("Hello,It's Derived");}
}
public class Test
{
public static void main (String[] args)
{
System.out.println("in the main");
Derived d=new Derived();
}
}
int main ()
{
derived test;
return 1;
}
输出结果:
I am Base
I am Derived
java的
import
java.util.
*
;
class Base
{
public Base () { init(); }
void init() { System.out.println("Hello,It'Base");}
}
class Derived extends Base
{
public Derived() { init();}
void init() { System.out.println("Hello,It's Derived");}
}
public class Test
{
public static void main (String[] args)
{
System.out.println("in the main");
Derived d=new Derived();
}
}
class Base
{
public Base () { init(); }
void init() { System.out.println("Hello,It'Base");}
}
class Derived extends Base
{
public Derived() { init();}
void init() { System.out.println("Hello,It's Derived");}
}
public class Test
{
public static void main (String[] args)
{
System.out.println("in the main");
Derived d=new Derived();
}
}
输出结果
Hello,It's Derived
Hello,It's Derived