继承的构造函数和其他变量的解决方法

时间:2018-07-13 07:54:45

标签: c++ constructor initialization superclass class-variables

我需要一种变通方法或一个好的解决方案来初始化基类和子类中的一堆常量类变量

问题很简单,我有一个带有两个构造函数的基类,并且在子类中有两个相同的构造函数

class BASE {
    int a;

    int func(float x) { // just a dummy to show that this function
        return (a = (int) x) + 2; // modifies a
    }
public:
    const int b;

    BASE(const int b) : b(b) {} // doesn't use a
    BASE(const float x) : a(0), b(func(x)) {}
};

struct SUB: public BASE {
    const int c;
    const int d;

    SUB(const int b) : BASE(b), c(b), d(c + 3) {}
    SUB(const float x) : BASE(x), c(b), d(c + 3) {}
};

在子类初始化其余变量之后,子类需要从BASE调用构造函数以从BASE初始化类变量

到目前为止还不错,但是问题在于,除了从BASE调用不同的构造函数之外,SUB的两个构造函数都做的完全相同

我想要类似的东西

    SUB() : c(b), d(c + 3) {} // BASE() needs to be defined
    SUB(const int b) : BASE(b), SUB() {}
    SUB(const float x) : BASE(x), SUB() {}

但这不起作用,因为“对委派构造函数的调用应是唯一的成员初始化程序” ...

将所有内容都移到初始化列表之外是行不通的,因为它们是const类变量

2 个答案:

答案 0 :(得分:2)

不幸的是,这是语言的规则,如果您有delegating constructor,则它必须是初始化列表的唯一部分。

您需要解决该限制,例如,通过复制默认的构造函数初始化器列表:

SUB(const int b) : BASE(b), c(b), d(c + 3) {}

答案 1 :(得分:2)

您可以为派生类创建“转发构造函数”:

struct SUB: public BASE {
    const int c;
    const int d;

    template <class... T>
    SUB(T&&... a) : BASE(std::forward<T>(a)...), c(b), d(c + 3) {}
};

这将接受任意参数并将其转发到BASE。当然,仅当使用对BASE有效的参数进行调用时,它才会编译,但适用于每种情况。

如果您想/需要超级正确,可以在诸如std::is_constructible<BASE, T&&...>之类的地方使用SFINAE来构造构造函数,但我不会打扰。