使用继承时,带有 CRTP 的类型定义不起作用
typedef with CRTP doesn't work when inheritance is used
是否有任何方法可以使用CTRP为继承关系中的类定义具有相同名称的类型?我尝试了以下代码,但从clang++
得到了error: member 'ptr_t' found in multiple base classes of different types
。
#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来实现这种行为,为什么禁止这样做?
您的问题与CRTP无关,而是与多重继承有关。Child
从两个基类继承了ptr_t
,并且两种类型都不同:shared_ptr<Parent>
和shared_ptr<Child>
。因此,编译器无法弄清楚main
中Child::ptr_t
所指的类型。
正如您所指出的,您必须使用Child
中的typedef
手动修复此问题(不过会使Pointable
基类变得无用)。
class Child : public Parent,
public Pointable<Child> {
public:
typedef Pointable<Child>::ptr_t ptr_t;
假设Child是从Parent公开派生的,如果不在Child的定义中添加一些内容,就无法在每个类型中以不同的方式定义相同的typedef。无论您如何定义继承,Child都将从Parent继承错误的typedef。
一种可能性是定义一个特征类
template<typename T> class Traits
{
public:
typedef std::shared_ptr<T> ptr_t;
}
显然,在这种情况下,这并没有给您带来什么好处,因为引用Traits::ptr_t比Child::ptt_t长。(但是,如果您有很多typedef,或者您希望以后能够更改指针类型,那么它可能会很有用。)
如果Child仅从Parent派生(而不是从Pointable显式派生),则它是Pointable
,确切地说是Pointabe<Parent>
,因为它是Parent,而Parent是Pointable。
Parent::ptr_t可以保存Child的实例,导致Child是Parent(至少在代码的意义上)。
我不知道你想用ptr_t做什么。您不确定确切的类型,但可以尝试在层次结构中执行dynamic_cast
。也许这就足够了。
- 有没有一种方法可以通过"typedef"为重新定义的基本类型定义特征和强制转换运算符
- 强枚举类型定义:Clang Bug 还是 C++11 标准不确定性?
- 列表参数的类型定义
- 使用模板化的键类型定义 std::map,该键类型基于作为参数接收的函数
- 关于 C++ 中的函数类型定义
- C++(和 ROS) - 包含与前向声明引用,设置默认值和类型定义
- 将使用/类型定义限制为类范围
- 模板类型定义?
- C++:模板类的类型定义
- 如何对命名空间限定类型进行类型定义?
- 此递归模板类型定义是否有效C++?
- 具有调整对齐方式的类型定义
- C++从抽象类型定义类成员
- 用于C++代码的 API 监视器类型定义 (XML)
- 如何将result_of与函数类型定义一起使用
- 在C++的适当类型定义位置
- 如何根据模板类型定义浮点常量?
- 如何为缺少预定义运算符而不扩展命名空间"std"的标准类型定义运算符>> (istream &, ...)?
- 参数化类的别名(或类型定义)内部类
- 如果我想从类型"T"定义元素的容器(来自 STL),那么"T"必须使用默认构造函数?