在构造函数中调用虚方法:Java和C ++之间的区别
在Java中:
class Base {
public Base() { System.out.println("Base::Base()"); virt(); }
void virt() { System.out.println("Base::virt()"); }
}
class Derived extends Base {
public Derived() { System.out.println("Derived::Derived()"); virt(); }
void virt() { System.out.println("Derived::virt()"); }
}
public class Main {
public static void main(String[] args) {
new Derived();
}
}
这将输出
Base::Base()
Derived::virt()
Derived::Derived()
Derived::virt()
但是,在C ++中,结果不同:
However, in C++ the result is different:
Base::Base()
Base::virt() // ← Not Derived::virt()
Derived::Derived()
Derived::virt()
(请参阅http://www.parashift.com/c++-faq-lite/calling-virtuals-from-ctors.html for C ++ code)
(See http://www.parashift.com/c++-faq-lite/calling-virtuals-from-ctors.html for C++ code)
Java和C ++之间有什么区别?是vtable初始化的时间吗?
What causes such a difference between Java and C++? Is it the time when vtable is initialized?
编辑:我明白Java和C ++机制。
I do understand Java and C++ mechanisms. What I want to know is the insights behind this design decision.
这两种方法都有明显的缺点:
Both approaches clearly have disadvatages:
- 在Java中,调用使用的方法不能正确使用
this
,因为它的成员 - 在C ++中,如果您不知道C ++如何构建类,则会调用非直观的方法(即不是派生类中的方法)。
- In Java, the call goes to a method which cannot use
this
properly because its members haven’t been initialised yet. - In C++, an unintuitive method (i.e. not the one in the derived class) is called if you don’t know how C++ constructs classes.
为什么每种语言都做的是一个开放的问题,但两者都可能声称是更安全的选择:C ++的方式防止使用未初始化的成员; Java的方法允许在一个类的构造函数(这是一个完全有效的用例)内部的多态语义(在某种程度上)。
Why each language does what it does is an open question but both probably claim to be the "safer" option: C++’s way prevents the use of uninitialsed members; Java’s approach allows polymorphic semantics (to some extent) inside a class’ constructor (which is a perfectly valid use-case).