关于c++ template多态——CRTP 模式

看了很多有关CRTP(Curiously Recurring Template Prattern)的介绍,知道CRTP是什么,但不知道究竟应该在什么情况下用,请高手回答。

为了便于说明,以下给出三种类的继承方式:

第一种,普通继承,没有虚函数,子类同名函数完全覆盖父类:

struct Base

{

void Func() { std::cout << " base's func" << std::endl; }

};

struct Drv : public Base

{

void Func() { std::cout << " drv's func" << std::endl; }

};

第二种,普通继承,用虚函数:

struct Base

{

virtual void Func() { std::cout << " base's func" << std::endl; }

};

struct Drv : public Base

{

void Func() { std::cout << " drv's func" << std::endl; }

};

第三种:采用CRTP模式:

template <typename Derived>

struct Base

{

void Func() { static_cast<Derived&>(*this).FuncImpl(); }

void FuncImpl() { std::cout << "base's func" << std::endl; }

};

struct Drv : public Base<Drv>

{

void FuncImpl() { std::cout << "drv's func" << std::endl; }

};

我想问的是,为什么需要第三种方式???在我看来第三种和第一种比并没有多大优势。

第一种方式实际仅仅实现了子类对父类的共享,即公共的操作写在父类,子类仅仅实现个性的细节。

第二种方式除实现共享外,可以用父类的指针或引用实现多态,即:

Base* p = new Drv; p->Func();

甚至可以将父类的指针搜集到容器,之后可以进行无区别地批量处理(假设Drv1, Drv2, Drv3...均继承Base):

/// 搜集

std::vector<Base* p> container;

container.push_back(new Drv1);

container.push_back(new Drv2);

container.push_back(new Drv3);

...

/// 批量处理

for (unsigned int i = 0; i < container.size(); ++i) {

container[i]->Func();

}

第三种方式没有虚函数,的确可以省去动态绑定所需的开销,而且能够用于虚函数无法应用的地方,如内联,或函数模板。但它与第一种方式的区别何在?

虽然也可以用父类指针实现多态:Base<Drv>* p = new Drv; p->Func();

但由于父类必须显式指定子类作为模板参数,从应用的角度说它的优势体现在哪?这和如下写法有何区别: Drv* p = new Drv; p->Func(); (用第一种方式就可以实现)

另外,采用CRTP能将父类指针存放于容器中,然后进行无区别地处理吗(如第二种方式一样)??

如果以上两点都做不到,我不知道为什么还要采用CRTP,而不直接用第一种方式??它的应用点到底在哪???或者能做到,如何做?

我模板只是初步了解,还请高手指教,非常感谢!!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值