我可以将 CRTP 与多个派生 类 一起使用,并以多态方式使用它们吗?
Can I use CRTP with multiple derived classes, and use them polymorphically?
我有这样的 classes 层次结构:
template <class Type>
class CrtpBase
{
protected:
Type& real_this()
{
return static_cast<Type&>(*this);
}
};
template <class ChildType>
class Base : CrtpBase<ChildType>
{
public:
void foo()
{
this->real_this().boo();
}
};
class Derived1 : public Base<Derived1>
{
public:
void boo { ... }
};
class Derived2 : public Base<Derived2>
{
public:
void boo { ... }
};
问题是,我想以这种方式使用我的 classes:
std::vector<Base*> base_vec;
base_vec.push_bach(new Derived1());
base_vec.push_bach(new Derived2());
.........
base_vec[0]->foo();
但这是不可能的,因为所有派生的 classes 的基础 class 是不同的(实际上 Base 根本不是一个类型,它是模板)。那么,有没有一种方法可以将 crtp 与多个派生的 classes 以及多态性一起使用?
确实有,你也需要添加合适的非模板库class:
class AbstractBase
{
public:
virtual ~AbstractBase() {}
virtual void foo() = 0;
};
template <class ChildType>
class Base : CrtpBase<ChildType>, public AbstactBase
{
void foo() override { this->real_this().boo(); }
};
然后,将向量声明为 std::vector<AbstractBase*>
。
这确实引入了动态分派的开销(您可能试图通过使用 CRTP 来避免),但是动态分派是在 C++ 中获得运行时多态性的唯一方法。
不过,它仍然是有益的。例如,如果 foo
的实现由所有派生的 classes 共享,但调用了许多不同的 boo
风格的函数(每个派生的 class 都有不同的那些的实现),你只需在调用 foo
时支付一次动态调度成本,然后在 内 foo
进行的所有调用都是静态调度的,CRTP-风格。
另一方面,如果只是在 foo
中调用一个类似 boo
的函数,您不妨将 boo
设为虚拟,将非虚拟 foo
进入基地,从而摆脱 CRTP。成本将是相同的:非虚拟调度 (foo
) 和虚拟调度 (boo
)。
旁注,您应该强烈考虑在 std::vector
中存储智能指针; 拥有 原始指针是不好的做法。
我有这样的 classes 层次结构:
template <class Type>
class CrtpBase
{
protected:
Type& real_this()
{
return static_cast<Type&>(*this);
}
};
template <class ChildType>
class Base : CrtpBase<ChildType>
{
public:
void foo()
{
this->real_this().boo();
}
};
class Derived1 : public Base<Derived1>
{
public:
void boo { ... }
};
class Derived2 : public Base<Derived2>
{
public:
void boo { ... }
};
问题是,我想以这种方式使用我的 classes:
std::vector<Base*> base_vec;
base_vec.push_bach(new Derived1());
base_vec.push_bach(new Derived2());
.........
base_vec[0]->foo();
但这是不可能的,因为所有派生的 classes 的基础 class 是不同的(实际上 Base 根本不是一个类型,它是模板)。那么,有没有一种方法可以将 crtp 与多个派生的 classes 以及多态性一起使用?
确实有,你也需要添加合适的非模板库class:
class AbstractBase
{
public:
virtual ~AbstractBase() {}
virtual void foo() = 0;
};
template <class ChildType>
class Base : CrtpBase<ChildType>, public AbstactBase
{
void foo() override { this->real_this().boo(); }
};
然后,将向量声明为 std::vector<AbstractBase*>
。
这确实引入了动态分派的开销(您可能试图通过使用 CRTP 来避免),但是动态分派是在 C++ 中获得运行时多态性的唯一方法。
不过,它仍然是有益的。例如,如果 foo
的实现由所有派生的 classes 共享,但调用了许多不同的 boo
风格的函数(每个派生的 class 都有不同的那些的实现),你只需在调用 foo
时支付一次动态调度成本,然后在 内 foo
进行的所有调用都是静态调度的,CRTP-风格。
另一方面,如果只是在 foo
中调用一个类似 boo
的函数,您不妨将 boo
设为虚拟,将非虚拟 foo
进入基地,从而摆脱 CRTP。成本将是相同的:非虚拟调度 (foo
) 和虚拟调度 (boo
)。
旁注,您应该强烈考虑在 std::vector
中存储智能指针; 拥有 原始指针是不好的做法。