Open utterances-bot opened 3 years ago
template <typename Derived>
class Shape_CRTP : public Shape {
public:
virtual Shape* Clone() const {
return new Derived(static_cast<Derived const&>(*this));
}
};
virtual 可以不用了
template <typename Derived> class Shape_CRTP : public Shape { public: virtual Shape* Clone() const { return new Derived(static_cast<Derived const&>(*this)); } };
virtual 可以不用了
多谢,似乎还需要加override
。
好文章
不过现在的需求是这样的,有一个工厂函数,返回一个Base,这个Derive1 和 Derive2都继承这个Base,现在相安无事
Base* FactoryCreate() {
switch (...)
case1: {
return Derive1*;
case2: {
return Derive2*;
.... // 还有很多Derive...
}
}
}
如果用CRTI,那么意味着我们的Base是一个template class,这可能会导致我们需要改写成
template <typename T>
Base<T>* FactoryCreate() {
switch (...)
case1: {
return Derive1*;
case2: {
return Derive2*;
.... // 还有很多Derive...
}
}
如果我们有另外一个类用了Base, 比如
class X {
Base* base
}
是不是也要改写成template class呢?
template <typename Derived> class X {
Base<Derived>* base
}
这需要我们在Create的时候就申明Derived类型,也就是说放弃了多态呀。感觉不是很实用。。。
@BowenXiao1999 我感觉可以分成接口类与实现类,接口类 IBase 用于类型擦除,实现类 BaseImpl 则是这种 CRTP 风格,大概长这样:
class IBase {
public:
virtual void func() = 0;
virtual ~IBase() = default;
};
template <typename Derived>
class BaseImpl : public IBase {
public:
void func() override {
static_cast<Derived*>(this)->funcImpl();
}
};
class Derived : public BaseImpl<Derived> {
public:
void funcImpl() {
// ...
}
};
是的,我也觉得这个是一种办法,不过对func的调用应该还是避免不了Virtual Function Call?不知道这种和Derived直接实现IBase的纯虚函数func的实现有多少性能上的差异。
@BowenXiao1999 如果需求就是运行期的dispatch,那这次virtual function call是免不了的。与上面方案相对应的传统方案,实际是IBase和Derived中间还有个Abstract类,负责提供具体实现的模板,其中Abstract与Derived之间还会有virtual function call。
可以参考ClickHouse的IAggregateFunction::addBatch
,它的功能实际是通过IAggregateFunctionHelper
提供的,后者转调用实现类的add
接口,但这里因为使用了CRTP,它知道实现类的具体类型,这次add
就不需要走虚函数。
Curiously Recurring Template Pattern(CRTP) | Fu Zhe's Blog
CRTPC++中有一种很特别的模式,称为Curiously Recurring Template Pattern,缩写是CRTP。从它的名字看,前三个词都是关键字。Curiously,意思是奇特的。Recurring,说明它是递归的。Template,说明它与模板有关。 最常见的CRTP形式就很符合这三个关键字: 12345678templateclass B
http://fuzhe1989.github.io/2018/04/21/crtp/