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

calling overridden methods from constructor in C++ vs Java

本文关键字:函数调用 覆盖 方法 vs C++ Java      更新时间:2023-10-16

构造函数调用被覆盖的方法在java和C++中有所不同。有人可以解释为什么他们的调度方法有何不同吗?

我知道C++和Java的设计和演变方式不同。但是,当涉及到从构造函数调用可重写的方法时,任何关于为什么语言规范被有意设计为这种方式的见解都会有所帮助。

我进行这项调查的动机是容易出错的检查: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 : %dn", complex.i_);
    return 0;
}

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

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

请记住,基类首先按声明顺序初始化;然后是

数据成员,按声明顺序初始化;然后构造函数运行。只有这样,对象才完成。

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