• C++多重继承


    多重继承:

    一个子类继承了多个基类 

    #include<iostream>
    #include<string>
    
    class Phone {
    public:
        Phone(const std::string& num) :m_num(num) { }
        void call(const std::string& num) {
            std::cout << "拨打号码:" << num << std::endl;
        }
    private:
        std::string m_num;
    
    };
    
    class Player {
    public:
        Player(const std::string& med) :m_med(med) {}
        void plar(const std::string& music) {
            std::cout << "正在播放:" << music << std::endl;
        }
    private:
        std::string m_med;
    };
    
    class Comp {
    public:
        Comp(const std::string& os) :m_os(os) {}
        void run(const std::string& app) {
            std::cout << m_os << "系统上运行:" << app << std::endl;
        }
    private:
        std::string m_os;
    };
    
    class Smartphoto :public Phone, public Player, public Comp {  //子类,继承了3个基类--多重继承
    public:
        Smartphoto(const std::string& num, const std::string& med, const std::string& os) :Phone(num), Player(med), Comp(os) {}//初始化函数
        //要调用各个基类的初始化函数
    
    };
    
    int main()
    {
        Smartphoto iphoto12("13116141117", "mp3", "windows");
        iphoto12.call("13116140005");
        iphoto12.plar("我的中国心");
        iphoto12.run("王者荣耀");
    
        Smartphoto* p = &iphoto12;
        Phone* p1 = p;//向上造型;p1=p,子类地址就是第一个基类的地址
        Player* p2 = p;
        Comp* p3 = p;
    
        std::cout << sizeof(std::string) << std::endl;  //不同系统大小可能不一样
        std::cout << "p=" << p << std::endl;
        std::cout << "p1=" << p1 << std::endl;
        std::cout << "p2=" << p2 << std::endl;
        std::cout << "p3=" << p3 << std::endl;
        //各指针指向各自子对象的首地址
    
        return 0;
    }

    重点掌握:

    运行输出内容:

     28是string类型占用的字节数(不同系统大小可能不一样)

    第一子对象的地址就是子对象的地址

    第二子对象与第一子对象的间隔就是第一子对象所有成员变量占用字节数的总和

    第三子对象与第二子对象的间隔就是第二子对象所有成员变量占用字节数的总和

     

    名字冲突问题

    解决方法一

    #include<iostream>
    #include<string>
    
    class A { 
    public:
        void func(void) {
        std::cout << "A的func函数" << std::endl;
        }
     };
    
    class AA {
    public:
        void func(int i) {
        std::cout << "AA的func函数" << std::endl;
        }
     };
    
    class B:public A, public AA {  
    public:
        
    };
    
    int main()
    {
        B b;
        //b.func();  //报错--不明确
        //原因:继承了两个func函数,不明确调用哪个
    
        b.A::func();  //加上类作用域
        return 0;
    }

    解决方法二

    #include<iostream>
    #include<string>
    
    class A { 
    public:
        void func(void) {
        std::cout << "A的func函数" << std::endl;
        }
     };
    
    class AA {
    public:
        void func(int i) {
        std::cout << "AA的func函数" << std::endl;
        }
     };
    
    class B:public A, public AA {  
    public:
        using A::func;
        using AA::func;//声明基类函数的作用域到当前类
        //两个函数构成了重载关系
    };
    
    int main()
    {
        B b;
        b.func();  
        b.func(100);
    
        return 0;
    }

    钻石继承

    继承关系图:

        

     这种继承关系叫钻石继承

    #include<iostream>
    #include<string>
    /*     钻石继承
                A          公共基类
               / 
              B   C        中间类
                /
                D          末端子类
    */
    
    class A { 
    public:
        A(int data):m_data(data){
            std::cout << "A的指针:" << this << ",size=" << sizeof(A) << std::endl;
        }
    protected:
        int m_data;
        
     };
    
    class B:public A {
    public:
        B(int data):A(data){
            std::cout << "B的指针:" << this << ",size=" << sizeof(B) << std::endl;
        }
        void set(int newdata) {
            m_data = newdata;
        }
     };
    
    class C:public A {  
    public:
        C(int data) :A(data) {
            std::cout << "C的指针:" << this << ",size=" << sizeof(C) << std::endl;
        }
        int get(void) {
            return m_data;
        }
    };
    
    class D :public B, public C {
    public:
        D(int data):B(data),C(data){
            std::cout << "D的指针:" << this << ",size=" << sizeof(D) << std::endl;
        }
    };
    
    int main()
    {
        D d(100);
        std::cout << d.get() << std::endl;  //100
        d.set(200);
        std::cout << d.get() << std::endl;  //100   这个值没有被修改
        //原因:看下面的理解图
    
        return 0;
    }

    理解图:

    在创建末端子类(D)对象时,会包含多个公共基类(A)子对象,通过末端子类去访问公共基类的成员,会因为继承路径不同,而导致结果不一致 

    虚继承 

    【虚继承目的:为了共享公共基类的成员变量】

    通过虚继承,可以让公共基类(A)子对象在末端子类(D)对象中实例唯一,为所有中间类共享,这样即使沿着不同继承路径所访问的成员一定是一致的 

    #include<iostream>
    #include<string>
    /*     钻石继承
                A          公共基类
               / 
              B   C        中间类
                /
                D          末端子类
    */
    
    class A { 
    public:
        A(short int data):m_data(data){
            std::cout << "A的指针:" << this << ",size=" << sizeof(A) << std::endl;
        }
    protected:
        short int m_data;
        
     };
    
    class B:virtual public A {  //virtual 虚继承
    public:
        B(short int data):A(data){
            std::cout << "B的指针:" << this << ",size=" << sizeof(B) << std::endl;
        }
        void set(short int newdata) {
            m_data = newdata;
        }
     };
    
    class C:virtual public A {  //virtual 虚继承
    public:
        C(short int data) :A(data) {
            std::cout << "C的指针:" << this << ",size=" << sizeof(C) << std::endl;
        }
        short int get(void) {
            return m_data;
        }
    };
    
    class D :public B, public C {
    public:
        //虚继承时,由末端子类负责构造公共基类子对象
        D(short int data):B(data),C(data),A(data){
            std::cout << "D的指针:" << this << ",size=" << sizeof(D) << std::endl;
        }
    };
    
    int main()
    {
        D d(100);
        std::cout << d.get() << std::endl;  //100
        d.set(200);
        std::cout << d.get() << std::endl;  //200
    
        return 0;
    }

    虚继承语法:在中间类添加虚继承;在末端子类实现基类构造 

    在虚继承中,基类也叫虚基类

     【个人理解:基类中的成员变量在各个虚继承的子类中是共享的】

    虚继承类型大小的理解---了解

     上面代码的返回值

     A类大小=2,因为short int类型占2个直接

    B类大小实际占用4个字节(就是虚表指针的大小),但是返回值是虚表指针大小+A类大小=6

    C类大小跟B类大小一样

    D类大小是两个虚表指针大小+A类大小=10

  • 相关阅读:
    魔术方法之__call与__callStatic方法
    thinkphp5 实现搜索分页能下一页保留搜索条件
    koa2
    mongodb
    nodejs
    小程序
    Vue学习
    js4
    扎心!来自互联网er的2019年度总结,看完笑着流泪……
    谈谈“奋斗逼!”
  • 原文地址:https://www.cnblogs.com/liming19680104/p/13585750.html
Copyright © 2020-2023  润新知