我可以调用虚函数来初始化基类子对象吗?

pre*_*eys 2 c++ virtual constructor ctor-initializer

我知道不应该在构造函数中直接或间接调用虚函数,但是这段代码运行正常.
我在这里安全吗?

#include <iostream>
#include <string>

struct A {
    A (const std::string& name) {std::cout << name << std::endl;}
    virtual std::string tag() const = 0;
};

struct B: A {
    B() : A (tag()) {}
    virtual std::string tag() const override {return "B";}
};

int main() {
    B b; // Output gives "B\n"
}
Run Code Online (Sandbox Code Playgroud)

如果没有,以下(基于评论)是否是正确的解决方法?

// Replacement for class B:

struct B: A {
    B() : A (name()) {}
    virtual std::string tag() const override {return name();}
private:
    static std::string name() {return "B";}  // use static function
};
Run Code Online (Sandbox Code Playgroud)

Ded*_*tor 5

在构造函数和/或析构函数中调用虚拟成员通常是可以的.

在初始化所有碱基之前,它在ctor初始化程序中是一个不同的游戏:

12.6.2初始化基础和成员 [class.base.init]

[...]
可以为正在构建的对象调用14个成员函数(包括虚拟成员函数,10.3).类似地,正在构造的对象可以是运算typeid符(5.2.8)或dynamic_cast(5.2.7)的操作数.但是,如果在基类的所有mem-initializer完成之前,在ctor-initializer(或直接或间接从ctor-initializer调用的函数)中执行这些操作,则操作的结果是不确定的.

  • @EJP:如果在ctor初始值设定项列表中显式指定基类初始值设定项,则可以执行.例如,与OP的原始代码示例完全一样.由于虚函数调用`tag()`用作基类初始化器的参数(在ctor初始化列表中),因此必须在*基类初始化器有机会完成之前调用此虚函数.这可能正是上面引用的意思. (3认同)