做推文的网站知乎,邢台移动网站建设公司,wordpress站内搜索框,wordpress 关闭插件更新一、继承
面向对象编程有三个特点#xff1a;封装、继承和多态。其中继承在其中起着承上启下的作用。一般来说#xff0c;继承现在和组合的应用比较难区分#xff0c;出于各种场景和目的#xff0c;往往各有千秋。但目前主流的观点#xff0c;一般是如果没有特殊情况封装、继承和多态。其中继承在其中起着承上启下的作用。一般来说继承现在和组合的应用比较难区分出于各种场景和目的往往各有千秋。但目前主流的观点一般是如果没有特殊情况比如需要处理数据的访问权限、重新实现功能多态都是推荐使用组合的。继承一个是复杂另外一个不灵活。人类更擅长的是组件拼装而不是重新造组件。同时组合更适合开发设计原则比如开闭原则、单一职责等等好像只有一个里氏替换不合适。 但是在有些时候儿继承还是必须要用的那么今天重点谈一下在模板中如何使用继承。
二、模板继承及方式
模板的继承一如普通类的继承形式是基本相同的可能有些实现上看上去比较复杂。在模板开发的继承中一般有四种形式的继承方式以父子类来描述继承不指明的为普通类即 1、父类为模板 类似于
template typename T
class Base {
};
class Derived:public Baseint{
};这里面有一个前文提到的CRTP模式
template class T
class Base
{// 基类方法可以通过模板继承的方式来访问继承类的成员
};
class Derived : public BaseDerived
{
};2、子类为模板
class Base {
};
template typename T
class Derived:public Base{
};3、父子类均为模板 此种情况又有两种形式
//第一种实例化父类模板参数
template typename T
class Base {
};
template typename T
class Derived:public Baseint{
};
//第二种非实例化父类模板参数
class Base {
};
template typename T
class Derived:public BaseT{
};
4、父类的模板参数被继承
template typename T
class Base {
};
class Derived:public T{
};此处没有谈多继承这个在编程时尽量避免。有兴趣可以自己搞一下。在父子类继承中如果父类是模板会出现在子类中访问父类变量无法直接访问的现象。需要使用父类的类名限制 Base ::basemember_;或者直接在变量前加this进行访问。 原因是继承的模板要进行两次编译每一次只处理和本身的数据相关也就是说只管自己的地盘什么 父类模板参数啥的都暂时忽略第二步再处理上面没有处理的模板参数部分。所以此时直接访问父类继承过来的变量和函数会找不到报错重要的要使用某种方式把这部分延期到第二步编译那么就没有什么 问题了。方法就是上面的两种方式这样编译器就明白这些不是本身模板的内容就放到第二步处理。 另外一个选择继承这里也没有说明什么 意思呢就是模板参数有N个但父类模板只用其中的N个比如有子类有三个模板参数父类只用了其中两个或者一个其它的为子类自用。这种其实上面的组合方式不再赘述但是下面会给出例子。
三、例程
下面看一个例程
#include iostream
namespace TT {//父类为模板
template typename T class BaseT {
public:BaseT() default;BaseT(int a) : d_(a) {std::cout call template Parent class BaseT std::endl;}~BaseT() {}protected:int d_ 0;
};
class Derived : public BaseTint {
public:// Derived() default;Derived(int a) : BaseTint(a) {std::cout call derived sub class no template! std::endl;std::cout Parent class Base d_: d_ std::endl;}Derived() : BaseTint(10) {std::cout call derived sub class no template 10! std::endl;std::cout Parent class Base d_: d_ std::endl;}~Derived() {}
};
//子类为模板
class Base {
public:Base() default;Base(int a) : d_(a) { std::cout call Parent class Base std::endl; }~Base() {}protected:int d_ 0;
};
template typename T class DerivedT : public Base {
public:DerivedT(){};DerivedT(int a) : Base(a) {std::cout sub template class call Parent class Base std::endl;std::cout Parent class Base d_: d_ std::endl;}~DerivedT() {}
};
//父子均为模板但父类特化
template typename TT class DerivedTTa : public BaseTint {
public:DerivedTTa() {std::cout sub a template class call init Parent template class BaseT std::endl;}DerivedTTa(int a) : BaseT(a), d_(a) {std::cout sub a template class call init Parent template class BaseT std::endl;std::cout Parent class Base d_: d_ std::endl;}~DerivedTTa() {}protected:TT d_ 0;
};
//父子均为模板但父类未特化
template typename TT class DerivedTTb : public BaseTTT {
public:DerivedTTb() {}DerivedTTb(TT a) : BaseTTT(a) {std::cout sub b template class call Parent template class BaseT std::endl;std::cout Parent class BaseT d_: this-d_ BaseTTT::d_ std::endl;}~DerivedTTb() {}
};
//继承模板参数
template typename T class DerivedP : public T {
public:DerivedP() {std::cout template class inherit template class Parameter std::endl;}DerivedP(int a) : T(a) {std::cout template class inherit template class Parameter std::endl;std::cout parameter a is: a std::endl;}~DerivedP() {}
};
//选择继承
template typename T, typename N, typename P
class DerivedPM : public BaseTN {
public:DerivedPM() {std::cout template class call template Mult class Parameter std::endl;};DerivedPM(T t, N n, P p) : BaseTN(n), t_(t), n_(n), p_(p) {std::cout template class call template Mult class Parameter std::endl;std::cout parameter t,n,p is: t n p std::endl;std::cout parameter d_ is: this-d_ std::endl;}protected:T t_;N n_;P p_;
};
} int main() {TT::Derived td;TT::Derived td1(10);TT::Derived dd;TT::DerivedTint tdt;TT::DerivedTint tdt1(10);TT::DerivedTTaint tdta;TT::DerivedTTaint tdta1(10);TT::DerivedTTbint tdtb;TT::DerivedTTbint tdtb1(10);TT::DerivedPTT::Base tdp;TT::DerivedPTT::BaseTTT::Base tdpbb;TT::DerivedPMint, int, int tddpm;TT::DerivedPMint, int, int tddpm1(1, 2, 3);return 0;
}例程不难关键看模板继承模板中那个父类d_如何访问有的为什么要加this(或Base:有的为什么不加模板一但特化便和普通类一致不需要this。仔细想一下就会越来越明白。那个CRTP的在前文有专门的分析说明此处不再举例。有兴趣可以 翻一下前面的例程
四、总结
模板不管用得多少 总会遇到一些很古怪的错误但这些错误其实是编译器不友好或者说模板比较复杂导致编译无法特别准确的提供一些信息造成的。所以重点还是要把模板的基础知识学清楚一点点的推导出来再配合相关的错误信息就可以较快的解决问题。 网上还有先写非模板代码然后 再用模板代码改写的。这样也是一个不错的方法虽然有点费事儿但只要用在复杂的情况下就好了。重点在于不断的反复的把模板的知识对照着代码编写熟悉后自然就渐渐明白道理再写就逐渐顺手多了。