首页 > 解决方案 > 尝试在我的初始化列表中使用虚函数

问题描述

我正在尝试使用必须初始化的 const 成员创建基类和派生类:

class baseClan
{
public:
    baseClan(const string firstName)
    :
    fullName(createFullName(firstName))
    {}
private:
    const string lastName = "Smith";
    const string fullName;
    virtual const string createFullName(string firstName) { return firstName + " " + lastName ; }
}

如何实现派生类,以便它可以使用不同实现的 createFullName?我正在查看此链接 https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctor-idiom 但似乎我被困在一块石头和一个坚硬的地方之间:第一种方法它提出(使用init)不适用于初始化列表;而在第二种方法中,它明确指出它无法处理我们需要访问在 Derived 中声明的实例数据的情况。

标签: c++inheritancederived-classdynamic-binding

解决方案


从构造函数或析构函数调用虚函数是危险的,应尽可能避免。所有 C++ 实现都应该调用在当前构造函数的层次结构级别定义的函数版本,而不是进一步。

构造函数中的虚函数工作方式不同。在创建派生类的对象时,首先创建的是基类的对象,也就是说派生类还没有被创建,虚函数还没有被覆盖。

我认为您提供的链接(C++ FAQ)已经描述了解决这个问题的所有可能方法。但我强烈建议重新考虑您的代码。

您可以应用稍微不同的方法。您可以使基本构造函数接受参数来初始化数据字段,然后在派生类中使用初始化列表将必要的参数(甚至可能来自虚函数)传递给基本构造函数。例如:

class A {
public:
    A(int a, int b) : a_(a), b_(b) { }
    virtual int getA() const = 0;
    virtual int getB() const = 0;
    void print() { cout << a_ << ' ' << b_ << endl; }
private:
    const int a_ = 0;
    const int b_ = 0;
};

class B : public A {
public:
    B() : A(getA(), getB()) { }
    int getA() const override { return 1; }
    int getB() const override { return 2; }
};

int main() {
    B b;
    b.print();
    return 0;
}

推荐阅读