在初始化时使用基类的const

时间:2017-11-03 10:01:27

标签: c++ inheritance constructor const

假设有一个带有常量值的基类,一个从基类派生的中间子类,以及一个派生自中间类的最终派生类。

如果我们想在派生类的初始化列表中使用常量,那么如何才能做到这一点?

以下是示例代码:

#include <iostream>

class Base{
    protected:
        const std::size_t c;

        Base() : c(64){}
};

class Intermediate : public Base{
    public:
        Intermediate(int val){
            std::cout << "In Intermediate c is " << c << std::endl; // In Intermediate c is 64
            std::cout << "However, val = " << val << std::endl;     // However, val = 10
        }
};

class Derived : public Intermediate{
    public:
        Derived(int val) : Intermediate(this->c+val){
            std::cout << "In Derived c is " << c << std::endl;      // In Derived c is 64
        }
};

int main(){
    Derived instance(10);

    return 0;
}

所需的输出为74,但是在调用Derived类的初始化列表时,c尚未初始化。

我看到的可能解决方案是:

  1. 使const static
  2. 创建一个setter方法
  3. 多重继承
  4. 但是,我想保持整体结构不变(初始化列表)而没有构造函数体,所以如何在初始化期间使用基类的const?

2 个答案:

答案 0 :(得分:2)

在处理构造函数之前,您已使用此值。 您已使用c符号作为构造函数的参数,因此您创建了鸡蛋问题。

启用编译器中的-Wall开关以捕获此类问题 编译器警告你,你正在做一些可疑的事情:

https://wandbox.org/permlink/DIYaSQQ4FQQwsmkO

prog.cc: In constructor 'Derived::Derived(int)':
prog.cc:20:47: warning: '*<unknown>.Derived::<anonymous>.Intermediate::<anonymous>.Base::c' is used uninitialized in this function [-Wuninitialized]
         Derived(int val) : Intermediate(this->c+val){
                                         ~~~~~~^

正确的修复方法是不使用幻数(在某种程度上ti是这个问题): https://wandbox.org/permlink/1nfa3eXP2XIhgRE8

class Base{
    protected:
        static const std::size_t cDefaultValue = 64;
        const std::size_t c;

        Base() : c(cDefaultValue){}
};

class Intermediate : public Base{
    public:
        Intermediate(int val){
            std::cout << "In Intermediate c is " << c << std::endl; // In Intermediate c is 64
            std::cout << "However, val = " << val << std::endl;     // However, val = 10
        }
};

class Derived : public Intermediate{
    public:
        Derived(int val) : Intermediate(cDefaultValue + val){
            std::cout << "In Derived c is " << c << std::endl;      // In Derived c is 64
        }
};

另一种解决方法是组合。可悲的是,大多数开发人员倾向于过度使用继承,在大多数情况下,组合是更好的选择。

答案 1 :(得分:1)

您只需要一个接受Base访问者的Intermediate中受保护的ctor。然后,您可以在基础上提供任何类型的访问者(=计算),可以由中级使用,因此具有多个后代。您甚至可以通过模板将其设为静态访问者。

{{1}}