zoukankan      html  css  js  c++  java
  • C++中的继承和多继承

    一、学习笔记

    1.继承

    class Student : public Person {
        ...
    }

    2.继承时权限
    派生类中可以直接访问父类的protected成员,但是不能访问其private成员,若继承时不写public,默认就是private继承。

    继承方式基类中的访问属性    public        protected        private
    public                   public        protected        隔离   
    protected                protected     protected        隔离
    private                  private       private          隔离

    (1) 无论哪种继承方式,在派生类的内部使用父类时并无差别
    (2) 不同的继承方式,会影响这两方面:外部代码对派生类的使用,派生类的子类对派生类成员的使用

    3.using更改继承成员的权限
    ①修改成员变量的
      在派生类中的public:下使用using Father::room_key;可以将父类的protected成员room_key提升为public权限,此时可以直接在main()中访问!
      在派生类中的private:下使用using Father::room_key;可以将父类的protected成员room_key降低为private权限,此时就不可以在类外进行访问!
      若在派生类中可以使用using关键字将父类的public成员降为private权限,这样子类的子类就继承不到这个属性了。
    ①修改成员函数的
      在派生类中的public:下使用using Father::getRoomKey;可以将父类的protected成员getRoomKey()成员函数提升为public权限。可以直接使用函数名而不是
    函数签名的原因是这里仅仅是修改权限,父类重载的所有getRoomKey()都变为public了,之后类外调用根据参数匹配规则不变。

    也就是说可以使用using关键字调整继承来的成员的访问权限,但前提是这些成员对你这个类可见。

    4.构造函数子类也会继承父类的,但是其构造的是从父类那里继承过来的部分。

    5.子类中若是实现了与父类的同名函数getName(),可以Parent::getName()来调用父类的getName(), 但是操作的成员变量是子类继承父类的部分。

    6.子类定义与继承来的可见的成员变量同名的成员变量也是可以的。重新定义函数签名和函数名都相同的函数叫做复写。

    7.继承的父类的成员函数中操作的成员变量都是子类继承于父类的。父类的成员函数操作的成员变量都是父类的,除非子类进行了复写。

    8.在子类的外部可以通过s1.Father::getRoomKey();调用父类的函数,在子类的内部可以通过Father::getRoomKey();调用父类的函数。

    9.多重继承

    class Sofabed: public Sofa, public Bed {
        ...
    }
    
    Sofabed s;
    s::Sofa::setWeight() //指明调用Sofa的setWeight()

    10.多继承会导致二义性,解决办法是使用虚继承
    解决:把共性的东西提炼出来,只保留一份备份,放在共有的父类Fourniture中,然后Sofa和Bed都虚继承Fourniture。

    class Sofa : virtual public Fourniture
    class Bed : virtual public Fourniture
    class Sofabed: public Sofa, public Bed

    11.虚继承内存分布
    虚继承的成员在Sofabed类中只会保留一份备份,也就是说Fourniture类中定义的成员只会在SofaBed类中只保留一份。

    12.要尽量避免使用多继承,它会使程序变得更加复杂,更容易出错。

    13.带有继承和虚继承的构造函数的调用次序
    先父后子:
      (1)先调用基类的构造函数
        ①先调用虚拟基类的构造函数,再调用一般基类的构造函数。注意是先把所有虚基类的构造函数执行完后再执行的一般基类的构造函数。
      (2)然后再调用自身的构造函数
        ①先调用对象成员的构造函数,然后再调用自己的构造函数。

    对于虚继承的基类,基类的构造函数只执行一次
    eg: 如下两次继承,Furniture和Verication3C,它两个的构造函数是被调用一次!
    class Soft : virtual public Furniture, virtual public Verication3C
    class Bed : virtual public Furniture, virtual public Verication3C


    14.子类的构造函数给父类的构造函数传参数

    class LeftRightSofabed : public Sofabed, virtual public LeftRightCom {
    private:
        Date date;
    public:
        LeftRightSofabed(char *str1) : Sofabed(str1), LeftRightCom(str1), date(str1) { //注意这里的data用的是成员名,而不是类名
            cout <<"LeftRightSofabed()"<<endl;
        }
    };

    试验发现,在子类中使用初始化列表初始化虚继承的类无法触发虚继承的类中的有参构造函数被调用,调用的还是无参构造函数。
    eg:上面代码中LeftRightCom()的有参构造函数不会被调用,调用的还是无参构造函数。

    二、例子

    1.单继承例子

    #include <iostream>
    
    using namespace std;
    
    class Father {
    private:
        int money;
        char *name;
    protected:
        int room_key;
    
        int getRoomKey(int) {
            cout << "getRoomKey(int) name=" << name << endl;
            return room_key;
        }
    public:
    
        int getRoomKey(void) {
            cout << "getRoomKey(void) name=" << name << endl;
            return room_key;
        }
        Father() {
            money = 100;
            room_key = 1;
            name = "father_begin";
            cout << "Father()" << endl;
        }
        Father(char *name) {
            this->name = name;
            cout << "Father(char *name)" << "name= " << this->name << endl;
        }
        ~Father() {
            cout << "~Father()" << endl;
        }
    
        int getMoney(void) {
            cout << "int getMoney(void)" << endl;
            return money;
        }
        void setMoney(int money) {
            cout << "void setMoney(int money)" << endl;
            this->money = money;
        }
    };
    
    
    class Son : public Father {
        char *name;
    
    public:
        using Father::room_key;
        using Father::getRoomKey;
        Son(char *name){
            this->name = name;
            cout << "Son()" << "name= " << this->name << endl;
        }
        ~Son() {
            cout << "~Son()" << "name= " << this->name << endl;
        }
        int getRoomKey(void) {
            Father::getRoomKey();
            cout << "getRoomKey(void) name=" << name << endl;
            return room_key;
        }
    
    };
    
    
    int main()
    {
    
        Son s1("son_name");
    
        s1.getRoomKey();
        s1.getRoomKey(1);
        s1.Father::getRoomKey();
        s1.getMoney();
    
        cout <<"s1.room_key= "<< s1.room_key << endl;
    
        return 0;
    }
    
    
    /*
    Father()
    Son()name= son_name
    getRoomKey(void) name=father_begin
    getRoomKey(void) name=son_name
    getRoomKey(int) name=father_begin
    getRoomKey(void) name=father_begin
    int getMoney(void)
    s1.room_key= 1
    ~Son()name= son_name
    ~Father()
    */

    2.多继承中使用虚继承来处理成员变量二义性问题

    #include <iostream>
    
    using namespace std;
    
    class Furniture {
        int weight;
    public:
        int size;
        int getWeight() {
            cout << "Furniture::getWeight()" << endl;
            return weight;
        }    
    };
    
    
    class Sofa : virtual public Furniture {
        int sofa;
    public:
        void getSofa() {
            cout << "Sofa::getSofa()" << endl;
        }
    };
    
    class Bed : virtual public Furniture {
        int bed;
    public:
        void getBed() {
            cout << "Bed::getBed()" << endl;
        }
    };
    
    
    
    class Sofabed : public Sofa, public Bed {
        int color;
    public:
        int getColor() {
            cout << "Sofabed::getColor()" << endl;
            return color;
        }
    
        int getSize() {
            cout << "Sofabed::getSize()" << endl;
            return size;        
        }
    };
    
    int main() {
    
        Sofa so;
        Bed be;
        Sofabed sb;
    
        so.getWeight();
        so.getSofa();
    
        be.getWeight();
        be.getBed();
    
        sb.getSize();
        sb.getSofa();
        sb.getBed();
        sb.getWeight();
    
    
        return 0;
    }
    
    /*
    Furniture::getWeight()
    Sofa::getSofa()
    Furniture::getWeight()
    Bed::getBed()
    Sofabed::getSize()
    Sofa::getSofa()
    Bed::getBed()
    Furniture::getWeight()
    */

    3.虚继承构造函数中调用父类构造函数的例子

    #include <iostream>
    
    using namespace std;
    
    
    class Furniture {
    public:
        Furniture() {
            cout << "Furniture()" << endl;
        }
        Furniture(char *abc) {
            cout << "Furniture(abc)" << endl;
        }
    };
    
    
    class Verication3C {
    public:
        Verication3C() {
            cout << "Verication3C()" << endl;
        }
        Verication3C(char *abc) {
            cout << "Verication3C(abc)" << endl;
        }
    };
    
    
    class Soft : virtual public Furniture, virtual public Verication3C {
    public:
        Soft() {
            cout << "Soft()" << endl;
        }
        Soft(char *abc) : Furniture(abc), Verication3C(abc) {
            cout << "Soft(abc)" << endl;
        }
    };
    
    class Bed : virtual public Furniture, virtual public Verication3C {
    public:
        Bed() {
            cout << "Bed()" << endl;
        }
        Bed(char *abc) : Furniture(abc), Verication3C(abc){
            cout << "Bed(abc)" << endl;
        }
    };
    
    class SoftBed : public Soft, public Bed {
    public:
        SoftBed() {
            cout << "SoftBed()" << endl;
        }
        SoftBed(char *abc) : Soft(abc), Bed(abc){
            cout << "SoftBed(abc)" << endl;
        }
    };
    
    
    class LeightWrightCom {
    public:
        LeightWrightCom() {
            cout << "LeightWrightCom()" << endl;
        }
        LeightWrightCom(char *abc) {
            cout << "LeightWrightCom(abc)" << endl;
        }
    };
    
    
    class Type {
    public:
        Type() {
            cout << "Type()" << endl;
        }
        Type(char *abc) {
            cout << "Type(abc)" << endl;
        }
    };
    
    
    class Date {
    public:
        Date() {
            cout << "Date()" << endl;
        }
        Date(char *abc) {
            cout << "Date(abc)" << endl;
        }    
    };
    
    class LeightWrightSofaBed : public SoftBed, virtual public LeightWrightCom {
        Type type;
        Date date;
    public:
        LeightWrightSofaBed() {
            cout << "LeightWrightSofaBed()" << endl;
        }
        LeightWrightSofaBed(char *abc) : SoftBed(abc), LeightWrightCom(abc), type(abc), date(abc) {
            cout << "LeightWrightSofaBed(abc)" << endl;
        }
    };
    
    
    
    int main()
    {
    
        LeightWrightSofaBed l1("lll");
    
        return 0;
    }
    
    /*
    Furniture() //没有调用有参构造函数!!
    Verication3C() //没有调用有参构造函数!!
    LeightWrightCom(abc) //调用了有参构造函数
    Soft(abc)
    Bed(abc)
    SoftBed(abc)
    Type(abc)
    Date(abc)
    LeightWrightSofaBed(abc)
    */
  • 相关阅读:
    linux mint 安装 SecureCRT
    Openstack 在VMware虚拟机ESXI和Workstation下安装需要更改参数
    应该了解的Openstack命令
    OpenStack网络详解
    qcow2、raw、vmdk等镜像格式
    OpenStack入门之【OpenStack-havana】之单网卡-All In One 安装(基于CentOS6.4)
    mint下截图工具shutter的安装和使用设置
    win10 与linux mint双系统 只能进入mint而无法进入windows的解决方案
    Linux mint 亮度调节
    linux中删除文件名称乱码
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/10628109.html
Copyright © 2011-2022 走看看