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

3

在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;
}

2
“这是有意设计成这样的吗?” - 你为什么会期望Java设计者和C++设计者之间进行了沟通呢?它们是不同的编程语言,独立设计和演进的。 - Jesper Juhl
1
C++和Java之间有很多不同之处;事实上,Java的一些部分是用C++实现的。我认为可以肯定地说,C++和Java之间的差异是有意为之的;否则我们就只需编写C++,而无需使用Java了。 - Elliott Frisch
@JesperJuhl 嗯.... - Elliott Frisch
5
我愿意为这项调查提供翻译。我觉得我们应该停止花费时间在这个“调查”上。学习Java时不应以C++作为指南或模板,因为它们是两种不同的语言,有不同的规则等等。 - PaulMcKenzie
4
C++的原因是“继承”还没有完成(如果它使用一个只存在于派生类中的成员变量呢?由于尚未初始化,所以必须使用基类版本)。我不清楚Java,但是看起来它只是默认初始化 - Artyer
显示剩余3条评论
1个回答

1

在构造函数或析构函数中调用虚函数表示当前对象的构造/析构状态。由于基类在实际类之前初始化,因此在基类构造函数中调用它将分派到基类函数。

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

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

通常认为,在构造函数和析构函数中调用动态分派函数是不好的做法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接