使用继承时,带有CRTP的typedef不起作用

时间:2012-02-02 15:27:56

标签: c++ inheritance crtp

有没有办法使用CTRP为继承关系中的类定义具有相同名称的类型?我尝试了以下代码,但从error: member 'ptr_t' found in multiple base classes of different types获得了clang++

#include <iostream>
#include <tr1/memory>

template <typename T> class Pointable {
public:
    // define a type `ptr_t` in the class `T` publicly
    typedef std::tr1::shared_ptr<T> ptr_t;
};

class Parent : public Pointable<Parent> {
public:
    Parent() {
        std::cout << "Parent created" << std::endl;
    }

    ~Parent() {
        std::cout << "Parent deleted" << std::endl;
    }
};

class Child : public Parent,
              public Pointable<Child> {
public:
    Child() {
        std::cout << "Child created" << std::endl;
    }

    ~Child() {
        std::cout << "Child deleted" << std::endl;
    }
};

int main(int argc, char** argv)
{
    Child::ptr_t child_ptr(new Child());
    Parent::ptr_t parent_ptr(new Parent());

    return 0;
}

当然,下面的一个是可以的(但它是多余的并且违反DRY原则)。

class Parent {
public:
    typedef std::tr1::shared_ptr<Parent> ptr_t;

    Parent() {
        std::cout << "Parent created" << std::endl;
    }

    ~Parent() {
        std::cout << "Parent deleted" << std::endl;
    }
};

class Child : public Parent {
public:
    typedef std::tr1::shared_ptr<Child> ptr_t;

    Child() {
        std::cout << "Child created" << std::endl;
    }

    ~Child() {
        std::cout << "Child deleted" << std::endl;
    }
};

如果使用CRTP无法实现此行为,为何禁止使用?

3 个答案:

答案 0 :(得分:2)

您的问题与CRTP无关,但具有多重继承。 Child从其基类继承ptr_t,两种类型都不同:shared_ptr<Parent>shared_ptr<Child>。因此,编译器无法通过Child::ptr_t中的main找出您的意思。

正如您所指出的,您必须使用typedef中的Child手动修复此问题(但Pointable基类无用)。

class Child : public Parent,
              public Pointable<Child> {
public:
    typedef Pointable<Child>::ptr_t ptr_t;

答案 1 :(得分:0)

假设Child是从Parent公开派生的,没有办法在每个中定义相同的typedef,而不在Child的定义中放置内容。但是,如果定义了继承,Child将从Parent继承错误的typedef。

一种可能性是定义特征类

  template<typename T> class Traits
  {
  public:
      typedef std::shared_ptr<T> ptr_t;
  }

显然在这种情况下,由于引用Traits :: ptr_t比Child :: ptr_t长,因此不会给你带来太大的好处。 (但是如果你有很多typedef,或者你希望以后能够更改指针类型,它可能会有用。)

答案 2 :(得分:0)

如果Child仅从Parent派生(并且不是来自Pointable的显式),则PointablePointabe<Parent>完全相同,因为它是父级,而父级是Pointable。

Parent :: ptr_t可以保存Child的实例,导致Child isa Parent(至少在代码意义上)。

我不知道你想用ptr_t做什么。您丢失了确切的类型,但您可以尝试在层次结构中执行dynamic_cast。也许这就够了。