• C++类模板继承关系


    一共有这三种关系:

    一、类模板从类模板派生

    首先明确一点,子类肯定是要实例化的。子类实例化的时候要调用父类的构造函数,所以父类也是要实例化的。所以子类实例化的时候必须也要将父类实例化,所以子类模板的参数也必须支持对于父类的实例化。
    看代码:

    实例(1)

    父类模板的实例化规则完全由子类掌握。

    template<typename T1, typename T2>
    class Base
    {
        T1 t1;
        T2 t2;
    public:
        Base(T1 a, T2 b):t1(a),t2(b){}
    
        void display(){
            cout<<t1<<" "<<t2<<endl;
        }
    };
    
    template<typename T1,typename T2>
    class Derived: public Base<T2,T1>
    {
        T1 t1;
        T2 t2;
    public:
        Derived(T1 a, T2 b): Base<T2, T1>(b,a),t1(a),t2(b){}
    
        void display(){
            Base<T2,T1>::display();
            cout<<endl;
            cout<<t1<<" "<<t2<<endl;
        }
    };
    
    int main(){
        Derived<int,string> d(1,"123");
        d.display();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    输出结果:

    123 1
    
    1 123
    
    • 1
    • 2
    • 3

    当Derived实例化之后,Base也会连带实例化。

    template<typename T1,typename T2>
    class Derived: public Base<T2,T1>
    
    • 1
    • 2

    继承的时候,子类控制父类如何实例化。

    实例(2)

    父类模板继承的时候部分实例化。

    template<typename T1, typename T2>
    class Base
    {
        T1 t1;
        T2 t2;
    public:
        Base(T1 a, T2 b):t1(a),t2(b){}
    
        void display(){
            cout<<t1<<" "<<t2<<endl;
        }
    };
    
    template<typename T1,typename T2>
    class Derived: public Base<T1,char>
    {
        T1 t1;
        T2 t2;
    public:
        Derived(T1 a, T2 b): Base<T1,char>(a,'b'),t1(a),t2(b){}
    
        void display(){
            Base<T1,char>::display();
            cout<<endl;
            cout<<t1<<" "<<t2<<endl;
        }
    };
    
    int main(){
        Derived<int,string> d(1,"123");
        d.display();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    输出:

    1 b
    
    1 123
    
    • 1
    • 2
    • 3

    当然,继承的时候也可以控制父类模板部分实例化,但是注意一点。部分实例化后,父类模板仍然是模板。

    实例(3)

    父类模板完全实例化

    template<typename T1, typename T2>
    class Base
    {
        T1 t1;
        T2 t2;
    public:
        Base(T1 a, T2 b):t1(a),t2(b){}
    
        void display(){
            cout<<t1<<" "<<t2<<endl;
        }
    };
    
    template<typename T1,typename T2>
    class Derived: public Base<int,string>
    {
        T1 t1;
        T2 t2;
    public:
        Derived(T1 a, T2 b): Base(a,b),t1(a),t2(b){}
    
        void display(){
            Base::display();
            cout<<endl;
            cout<<t1<<" "<<t2<<endl;
        }
    };
    
    int main(){
        Derived<int,string> d(1,"123");
        d.display();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    输出结果:

    1 123
    
    1 123
    
    • 1
    • 2
    • 3

    这种情况,完全可以将父类模板看作一个普普通通的类,因为已经彻底实例化了。
    我们可以看到一个有意思是事情,只有彻底实例化的模板,在调用构造函数和display()的时候不需要指定模板实例化类型,原因我会在后续的博文里面解释。

    二、类模板从普通类派生

    class Base
    {
        int t1;
        int t2;
    public:
        Base(int a, int b):t1(a),t2(b){}
    
        void display(){
            cout<<t1<<" "<<t2<<endl;
        }
    };
    
    template<typename T1,typename T2>
    class Derived: public Base
    {
        T1 t1;
        T2 t2;
    public:
        Derived(T1 a, T2 b): Base(123,456),t1(a),t2(b){}
    
        void display(){
            Base::display();
            cout<<endl;
            cout<<t1<<" "<<t2<<endl;
        }
    };
    
    int main(){
        Derived<int,string> d(1,"123");
        d.display();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    这个可能是最常用的用法了。大家只需要牢牢记住一点:子类模板实例化的时候,其行为与结构是否合理。
    其实,这个完全等价于上一小节的实例(3)。

    三、普通类从模板类派生

    不说那些虚的了,记住一句话:
    普通类不能继承于模板类!!!
    模板类如果想被普通类继承,那么必须要实例化!!!

    四、总结

    上面的种种现象,只需要记住一下几个点,全部都可以解释通:
    (1)子类构造对象的时候,必然要给父类构造对象;
    (2)构造对象的前提是明确类型,没有实例化的模板是不能构造对象的。
    (3)子类确定类型的时候,如果父类的类型不明确,那么就无法构造对象。

  • 相关阅读:
    day82【Leetcode】
    SQL注入——预编译CASE注入
    Python 实现的简易数据库管理系统 (DBMS)
    NoSQL常用数据结构 LSM Tree 简介
    SpringMVC进阶:常用注解、参数传递和请求响应以及页面跳转
    【C语言】【strcpy的使用和模拟实现】
    服务器监控软件(一 、大致讲解篇)
    【Vue基础系列】vue-router 万字详解,一篇彻底搞懂
    【Linux】CentOS 7安装 MySQL
    jQuery基础知识
  • 原文地址:https://blog.csdn.net/jiexianxiaogege/article/details/134321952