【问题标题】:Curiously recurring template patterm: double inheritance奇怪重复的模板模式:双重继承
【发布时间】:2012-10-23 13:18:14
【问题描述】:

我有以下几点:

class Base
{
protected:
    std::string _name;

public:
    virtual ~Base(){}

    const std::string &name;

    Base()
        : _name ("(no name)")
        , name(_name)
    {}
};

template <typename T>
class BaseH : public Base
{
public:
    virtual ~BaseH() {}
    BaseH() : Base() {}

    T& operator~(){ ; return static_cast<T&>(*this);}
};

class One : public BaseH<One>
{
public:
    One() : BaseH<One>() { _name = "One"; }

};

class Two
    : public One
    , public BaseH<Two>
{
public:
    Two() : BaseH<Two>() { _name = "Two"; }

};


int main(int argc, char *argv[])
{
    std::cout << Two().name << std::endl;

    return 0;
}

我想从OneBaseH&lt;Two&gt; 派生Two,因为TwoOne 的特化,而BaseH 中的operator~ 必须始终返回类型为调用它的对象。

编译错误明显是:

In constructor ‘Two::Two()’:
  error: reference to ‘_name’ is ambiguous
  error: candidates are: std::string Base::_name
  error:                 std::string Base::_name
In function ‘int main(int, char**)’:
  error: request for member ‘name’ is ambiguous
  error: candidates are: const string& Base::name
  error:                 const string& Base::name

在通过构造函数委托设置const 引用时,如何使OneTwo 中的_namename 都可访问?最干净的方法是什么?

【问题讨论】:

  • 我怀疑这是否真的是CRTP。或者至少通过 virtual 函数,你没有利用它。
  • @iammilind:不确定你的意思,但就其价值而言,这当然是“真实”代码的一小部分摘录
  • CRTP 通常在您想消除由于 virtual 函数引起的开销时很有用(请参阅 wiki 链接)。在代码示例中,它没有利用它。您发布的可能是另一种形式的 CRTP。
  • @iammilind:您对如何完成上述操作有什么建议吗?
  • 从您的代码中,我认为在任何类中都不需要 virtual 析构函数,因为您使用的是 CRTP。如果您使用new T/delete pT 将内存分配给BaseH&lt;T&gt;*,那么可能需要进行一些调整。但这必须详细讨论,值得另一个问题。您还可以提及您的设计目标,例如您想要实现的目标。

标签: c++ oop design-patterns inheritance crtp


【解决方案1】:

看起来你有diamond problem。你试过virtual inheritance吗?

例如:

template <typename T>
class BaseH : virtual public Base
{
    // ...
};

class One : virtual public BaseH<One>
{
    // ...
};

编辑:在此处进一步阅读钻石问题:http://www.cprogramming.com/tutorial/virtual_inheritance.html

【讨论】:

  • 看,我知道我以前见过这个问题 :) 谢谢,现在可以使用了。
  • C++ 的另一个怪癖。没问题:)