从构造函数调用重写的方法在Java和C ++中有所不同。 有人可以解释为什么他们的派遣方法有何不同吗?
我了解C ++和Java的设计和发展是不同的。但是,当涉及到从构造函数中调用可重写方法时,任何对为何有意以这种方式设计语言规范的见解都会有所帮助。
我进行此调查的动机是ErrorProne检查:http://errorprone.info/bugpattern/ConstructorInvokesOverridable
这是返回1的Java代码
class Ideone
{
static class Simple {
public int i;
Simple() {
this.i = func();
}
public int func() {
return 2;
}
}
static class Complex extends Simple {
@Override
public int func() {
return 1;
}
}
public static void main (String[] args) throws java.lang.Exception
{
Complex c = new Complex();
System.out.println(c.i);
}
}
这是返回2的c ++代码
#include <iostream>
using namespace std;
class Simple {
public:
Simple(int i) { i_ = func(); }
virtual int func() { return 2; }
int i_;
};
class Complex : public Simple {
public:
Complex(int i) : Simple(i) {}
int func() override { return 1; }
};
int main() {
// your code goes here
Complex complex(2);
printf("Val is : %d\n", complex.i_);
return 0;
}
答案 0 :(得分:1)
在构造函数或析构函数中调用虚拟函数表示当前对象的构造/破坏状态。当基类在实际类之前被初始化时,在基类构造函数中对其进行调用将分派给基类函数。
此时未初始化派生类成员,因此尚未确定派生类所施加的任何不变性。因此,派生类函数可能无法正确执行其工作。
请记住,首先按照声明的顺序初始化基类。然后是数据成员,按照声明的顺序;然后构造函数运行。只有这样,对象才完整。
在ctor和dtor中调用动态分派函数通常被认为是不好的做法。