将基类的const成员初始化为派生类

时间:2011-09-27 11:49:43

标签: c++ inheritance

public:
    const int x;
    base():x(5){}

};

class der : public base {
public:
    der():x(10){}
};

der d;

我的目标是当创建基类的实例时,它将x初始化为5,并且当创建类的实例时,它将x初始化为10.但是编译器给出了错误。 由于x是从类库继承的,为什么它会出错?

4 个答案:

答案 0 :(得分:7)

你可以通过一点调整来完成这项工作......

#include <cassert>

class base
{
public:
    const int x;
    base()
        :x(5)
    {
    }

protected:
    base(const int default_x)
        :x(default_x)
    {
    }
};

class der: public base
{
public:
    der()
        :base(10)
    {
    }
};

struct der2: public base
{
    der2()
        :base()
    {
    }
};

int main()
{
    base b;
    assert(b.x == 5);
    der d;
    assert(d.x == 10);
    der2 d2;
    assert(d2.x == 5);
    return d.x;
}

这提供了一个可由派生类访问的构造函数,它可以提供一个默认值来初始化base.x

答案 1 :(得分:5)

您无法在派生类中的构造函数的初始值设定项列表中初始化基类成员。初始化列表可以包含此类中的基础和成员,但不包含基础中的成员。

不可否认,这方面的标准并不完全清楚。 C ++ 03的12.6.2 / 2:

  

除非mem-initializer-id命名为非静态数据成员   构造函数的类或该类的直接或虚拟基础   mem-initializer格式不正确。

它表示“(构造函数类的非静态数据成员)或(直接或虚拟基础)”。它并不意味着“(构造函数的类或直接或虚拟基础)的非静态数据成员”。这个句子含糊不清,但是如果你读了二读,你根本就不能在初始化列表中放置基数,标准中的下一句话就清楚地表明你可以。

至于为什么不允许,这是一个标准的理由问题,我猜测标准作者的动机。但基本上是因为基类有责任初始化自己的成员,而不是派生类的责任。

您可能应该向int添加base构造函数。

答案 2 :(得分:1)

这很有效。

class base {
public:
    static const int x = 5;
};

class der : public base {
public:
    static const int x = 10;
};

如果要根据构造函数更改x,则必须使其为非静态。

非静态const与编译后的非const变量相同。如果要将成员变量强制为只读,请使用非静态const。如果要设置其范围仅限于单个类的常量,请使用static const。

答案 3 :(得分:0)

与原始问题相比,这可能过度设计,但请考虑:

template <typename T, class C, int index=0> 
// C and index just to avoid ambiguity
class constant_member {
    const T m;
    constant_member (T m_) :m(m_) {}
};

class base : virtual public constant_member<int, base> {
public:
    base () : constant_member<int, base>(5) {}
    int x () const { return constant_member<int, base>::m; }
};

class der : public base {
public:
    der () : constant_member<int, base>(10) {}
};

class der2 : public der{
public:
    der2 () {} // ill-formed: no match for 
               // constant_member<int, base>::constant_member() 
};

评论:这是冗长的,非显而易见的(对于初学者来说可能无法理解),转换为virtual基类只是为了读取成员变量是非常低效的。我真的建议这是一个真实世界的解决方案。