【问题标题】:May I call a virtual function to initialize a base-class sub-object?我可以调用虚函数来初始化基类子对象吗?
【发布时间】:2014-11-03 11:24:27
【问题描述】:

我知道在构造函数中不应该直接或间接调用虚函数,但是这段代码运行良好。
我这里的东西安全吗?

#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"
}

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

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

【问题讨论】:

  • “我知道虚函数不应该在构造函数中直接或间接调用”...这是一个新的...
  • @重复数据删除器。根据您的评论,我在上面写了一个不同的版本。这是你的建议吗?
  • @Deduplicator 什么时候是 UB?!
  • @LightnessRacesinOrbit:恢复和扩展评论:在 ctor-initializer 中调用虚函数是 UB,因为标准在 12.6.2 (14) 中是这样说的。
  • @Deduplicator Touché。具体来说,它是 UB 只是因为基础尚未完成初始化。

标签: c++ constructor virtual ctor-initializer


【解决方案1】:

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

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

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

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

【讨论】:

  • 好的,这说服了我使用您对静态函数重定向的建议进行我的第二个设计。
  • @prestokeys:可以,直接调用静态函数。
  • 最后一句不就是指typeid和dynamic_cast吗? ctor-initialiser 怎么可能在基类的 mem-initialiser 之前执行?
  • @EJP: MyClass() :MyBase(dynamic_cast&lt;MyBase*&gt;(this)) {} 和类似的。
  • @EJP:如果您在 ctor 初始化程序列表中明确指定基类初始化程序,它可以执行。例如。与 OP 的原始代码示例完全相同。由于虚函数调用tag() 用作基类初始化器的参数(在ctor 初始化器列表中),因此必须在 基类初始化器有机会完成之前调用此虚函数。这可能正是上面引用的意思。
猜你喜欢
  • 2011-10-07
  • 2019-01-24
  • 2019-12-01
  • 2023-03-16
  • 1970-01-01
  • 2016-06-17
  • 2019-02-06
  • 1970-01-01
相关资源
最近更新 更多