2012-02-02 56 views
1

有没有什么方法可以通过使用CTRP来为继承关系中的类定义一个同名的类型?我尝试了下面的代码,但从clang++得到error: member 'ptr_t' found in multiple base classes of different types当使用继承时,使用CRTP的typedef不起作用

#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来实现这种行为,为什么禁止?

回答

2

您的问题与CRTP无关,但具有多重继承。 Child从它的两个基类继承ptr_t,并且两种类型都不相同:shared_ptr<Parent>shared_ptr<Child>。因此,编译器无法确定mainChild::ptr_t的含义。

正如你所指出的那样,你必须使用typedefChild中手动解决这个问题(尽管你的Pointable基类没用)。

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

想通了。非常感谢! – mooz 2012-02-02 16:18:50

0

承担起子女衍生公开从父,有没有办法有不同的定义各不把一些儿童的定义中相同的typedef。但是,您定义了继承,Child将从Parent继承错误的typedef。

一种可能性是定义一个traits类

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

显然,在这种情况下不会获得你多少,因为参照性状:: ptr_t比儿童:: ptr_t更长。 (但是如果你有很多类型定义,或者你希望能够稍后改变指针类型,它可能会很有用。)

0

如果孩子只从父项派生(而不是从显式指向),它是一个Pointable准确地说是一个Pointabe<Parent>,导致它是一个父母,而父母是一个指针。

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

我不知道你想用ptr_t做什么。你没有确切的类型,但你可以尝试在层次结构上做一个dynamic_cast。也许这就够了。