关于c++ template多态——CRTP 模式
2017-06-28 20:08
337 查看
看了很多有关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,而不直接用第一种方式??它的应用点到底在哪???或者能做到,如何做?
我模板只是初步了解,还请高手指教,非常感谢!!!!
为了便于说明,以下给出三种类的继承方式:
第一种,普通继承,没有虚函数,子类同名函数完全覆盖父类:
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,而不直接用第一种方式??它的应用点到底在哪???或者能做到,如何做?
我模板只是初步了解,还请高手指教,非常感谢!!!!
相关文章推荐
- C++ 模板:奇特递归模板模式(Curiously Recurring Template Pattern -CRTP)和 静多态(Static polymorphism)
- C++惯用法:奇特的递归模板模式(Curiously Recurring Template Pattern,CRTP,Mixin-from-above)
- 关于C++ template的定义
- C++经典对话上关于模式的两篇好文章
- 设计模式C++描述----02.模板(Template)模式
- 关于C++多态的理解【zz】
- 关于C++多态的理解
- C++实践::Template实现Observer模式
- 关于c++的多态
- C++惯用法:奇特的递归模板模式(Curiously Recurring Template Pattern,CRTP,Mixin-from-above)
- C++实践::Template实现Observer模式
- 关于c++中原型模式的一个问题,请告诉进来帮忙指点一下
- 关于C++中私有继承后虚函数的访问权限与私有继承后多态的问题
- C/C++问答(3):关于构造和析构函数使用多态
- [GoF设计模式]Bridge模式和Template模式的C++实现
- 关于2012腾讯面试题的C++多态问题
- C++实践::Template实现Observer模式
- 关于C++单件模式释放对象
- 关于C++中的重载和多态
- 关于C++多态的理解