在C ++和Java中从构造函数调用覆盖的方法

时间:2019-06-09 18:23:22

标签: java c++ constructor

从构造函数调用重写的方法在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;
}

1 个答案:

答案 0 :(得分:1)

在构造函数或析构函数中调用虚拟函数表示当前对象的构造/破坏状态。当基类在实际类之前被初始化时,在基类构造函数中对其进行调用将分派给基类函数。

此时未初始化派生类成员,因此尚未确定派生类所施加的任何不变性。因此,派生类函数可能无法正确执行其工作。

请记住,首先按照声明的顺序初始化基类。然后是数据成员,按照声明的顺序;然后构造函数运行。只有这样,对象才完整。

在ctor和dtor中调用动态分派函数通常被认为是不好的做法。