C++ 何时在构造函数中调用虚函数是安全的

C++ 何时在构造函数中调用虚函数是安全的,c++,constructor,virtual-functions,C++,Constructor,Virtual Functions,我有一些代码,我真的想从构造函数调用一个虚拟方法。我知道这被认为是不安全的,而且我对对象构造也有足够的了解。我也没有经历过。目前我的代码正在运行,我认为应该可以,但我想确定一下 以下是我正在做的: 我有一些类层次结构,还有一个普通的公共函数,它像往常一样只是转发到一个私有虚拟方法。但是,我确实希望在构建对象时调用此公共方法,因为它将所有数据填充到对象中。我绝对肯定这个虚拟调用来自于叶类,因为从类层次结构的任何其他部分使用这个虚拟方法根本没有意义 因此,在我看来,对象创建应该在我进行虚拟调用后完成

我有一些代码,我真的想从构造函数调用一个虚拟方法。我知道这被认为是不安全的,而且我对对象构造也有足够的了解。我也没有经历过。目前我的代码正在运行,我认为应该可以,但我想确定一下

以下是我正在做的:

我有一些类层次结构,还有一个普通的公共函数,它像往常一样只是转发到一个私有虚拟方法。但是,我确实希望在构建对象时调用此公共方法,因为它将所有数据填充到对象中。我绝对肯定这个虚拟调用来自于叶类,因为从类层次结构的任何其他部分使用这个虚拟方法根本没有意义


因此,在我看来,对象创建应该在我进行虚拟调用后完成,一切都应该很好。还有什么可能出错的吗?我想我必须用一些大的注释来标记逻辑的这一部分,以解释为什么这个逻辑永远不应该被移动到任何基本类,即使它看起来可以被移动。但是除了其他程序员的愚蠢之外,我应该没问题,不是吗?

当调用构造函数时,类被设置为该类的实例,而不是派生类。不能从基构造函数调用派生类的虚拟函数。当您到达最派生类的构造函数时,应该可以安全地调用所有虚拟函数


如果希望确保有人不会进行错误的调用,请在基类中定义虚拟函数,并在调用时让它断言和/或引发异常。

调用构造函数时,将该类设置为该类的实例,而不是派生类。不能从基构造函数调用派生类的虚拟函数。当您到达最派生类的构造函数时,应该可以安全地调用所有虚拟函数


如果您希望确保有人不会进行错误的调用,请在基类中定义虚拟函数,并让它在调用时断言和/或抛出异常。

调用构造函数或析构函数中的任何非抽象虚拟函数绝对安全!然而,它的行为可能会令人困惑,因为它可能不会做预期的事情。在执行类的构造函数时,对象的静态和动态类型都是构造函数的类型。也就是说,虚拟函数永远不会被分派到另一个派生类的重写。除此之外,虚拟分派实际上是有效的:例如,当通过基类指针或引用调用虚拟函数时,会正确地分派到当前正在构造函数或析构函数的类中的重写。例如(可能有很多拼写错误,因为我目前无法理解这段代码):

#包括
结构A{
虚拟~A(){}
虚空f(){std::cout f();}
};
结构B:A{
B(){this->g();}//这个打印'B::f()'

void f(){std::cout在构造函数或析构函数中调用任何非抽象的虚拟函数是绝对安全的!但是,它的行为可能会令人困惑,因为它可能不会执行预期的操作。在执行类的构造函数时,对象的静态和动态类型就是构造函数的类型。也就是说,虚拟函数将决不能调度到另一个派生类的重写。除此之外,虚拟调度实际上是有效的:例如,当通过基类指针或引用调用虚拟函数时,会正确地调度到当前正在构造函数或析构函数的类中的重写。例如(可能有很多拼写错误,因为我目前无法理解这段代码):

#包括
结构A{
虚拟~A(){}
虚空f(){std::cout f();}
};
结构B:A{
B(){this->g();}//这个打印'B::f()'

void f(){std::cout这条规则并不是说你需要在一个叶类中,而是要意识到当你从
Foo::Foo(…)
调用一个成员时,这个对象就是一个
Foo
,即使它正在变成一个
(假设
Foo
是从
Bar
派生的,并且您正在构建一个
Bar
实例),这是100%可靠的

否则,成员是虚拟的这一事实就不那么重要了。非虚拟函数也会出现其他陷阱:如果调用一个虚拟或非虚拟方法,该方法假定对象已完全构造,但在此之前在构造函数中调用它,那么您也会遇到问题。不是吗这些都是很难确定的情况,因为不仅你调用的函数必须是好的,它调用的所有函数都必须是好的


听起来你没有问题,这只是那些容易出现错误的地方之一。

规则并不是说你需要在一个叶类中,而是要意识到当你从
Foo::Foo(…)
进行成员调用时,对象就是一个
Foo
,即使它正在变成一个
Bar
(假设
Foo
是从
Bar
派生的,并且您正在构建一个
Bar
实例),这是100%可靠的

否则,成员是虚拟的这一事实就不那么重要了。非虚拟函数也会出现其他陷阱:如果调用一个虚拟或非虚拟方法,该方法假定对象已完全构造,但在此之前在构造函数中调用它,那么您也会遇到问题。不是吗这些都是很难确定的情况,因为不仅你调用的函数必须是好的,它调用的所有函数都必须是好的

听起来你没有问题,这只是容易出现错误的地方之一。

只要
#include <iostream>
struct A {
    virtual ~A() {}
    virtual void f() { std::cout << "A::f()\n"; }
    void g() { this->f(); }
};
struct B: A {
    B() { this->g(); } // this prints 'B::f()'
    void f() { std::cout << "B::f()\n"; }
};
struct C: B {
    void f() { std::cout << "C::f()\n"; } // not called from B::B()
};

int main() {
    C c;
}