1、继承:

通过继承定义一个类,它们的类型之间的关系建模,共享共有的东西,实现各自本质不同的东西。

C++的“继承”特性可以提高程序的可复用性。

继承定义格式:


wKiom1cIoCPD6ffCAAAkHgWtV5E225.png


2、类的大小:

class Base

{

public:

    Base(int data)

    {

        cout << data << endl;

        cout << "Base()" << this << endl;

    }

    ~Base()

    {

        cout << "~Base()" << endl;

    }

private:

    int _pri;

protected:

    int _pro;

public:

    int _pub;

};   

//求类大小时,只求数据成员的大小三个int类型的数据成员,所以大小为12

class Base1

{

public:

    Base1(int data)

    {

        cout << "Base1()" << endl;

    }

    ~Base1()

    {

        cout << "~Base1()" << endl;

    }

};

//当类没有数据成员时,通常系统都会给一个值为1的空间,因为类的大小不可能为0,但是系统又要给类分配空间,为了节省空间,会分配最小空间

class Test

{

public:

    Test(int data)

    {

        cout << "Test()" << endl;

    }

    ~Test()

    {

        cout << "~Test()" << endl;

    }

};

class Derive :public Base, public Base1

{

public:

    Derive()

        :d(10)

        , Base1(10)

        , Base(20)

    {

        cout << "Derive()" << this << endl;

    }

    ~Derive()

    {

        cout << "~Derive()" << endl;

    }

private:

    int _dPri;

protected:

    int _dPro;

public:

    int _dPub;

    int _pri;

    Test d;

};

int main()

{

    cout << sizeof(Base) << endl;  //12

    cout << sizeof(Base1) << endl;  //1

    cout << sizeof(Derive) << endl;  //32

    system("pause");

    return 0;

}

wKioL1cLTLOhj8FFAABMhx2umdo195.png

3、类的访问:

class Base

{

public:

    Base(int data)

    {

        cout << data << endl;

        cout << "Base()" << this << endl;

    }

    void Show()

    {

        cout << "Base::Show()" << endl;

        cout << "_pri=" << _pri << endl;

        cout << "_pro=" << _pro << endl;

        cout << "_pub=" << _pub << endl;

    }

    ~Base()

    {

        cout << "~Base()" << endl;

    }

private:

    int _pri;

protected:

    int _pro;

public:

    int _pub;

};

class Base1

{

public:

    Base1(int data)

    {

        cout << "Base1()" << endl;

    }

    ~Base1()

    {

        cout << "~Base1()" << endl;

    }

};

class Test

{

public:

    Test(int data)

    {

        cout << "Test()" << endl;

    }

    ~Test()

    {

        cout << "~Test()" << endl;

    }

};

class Derive :public Base, public Base1

{

public:

    Derive()

        :d(10)

        , Base1(10)

        , Base(20)

    {

        cout << "Derive()" << this << endl;

    }

    ~Derive()

    {

        cout << "~Derive()" << endl;

    }

    void Display()

    { 

        cout << "_pri=" << _pri << endl;

        cout << "_pro=" <<& _pro << endl;

        cout << "-pub=" << &_pub << endl;

        cout << "_dPri=" << &_dPri << endl;

        cout << "_dPro=" << &_dPro << endl;

        cout << "_dPub=" << &_dPub << endl;

    }

    void Show()

    {

        _pri = 10;

        //Base::_pri = 10;  

        //私有成员只能在基类访问,在派生类和其他地方都不能访问 

        cout << "Derive::Show()" << endl;

    }

private:

    int _dPri;

protected:

    int _dPro;

public:

    int _dPub;

    int _pri;

    Test d;

};

int main()

{

    cout << sizeof(Base) << endl;  //12

    cout << sizeof(Base1) << endl;  //1

    cout << sizeof(Derive) << endl;  //32

    Derive d; 

    //调用构造函数时,先进Base类调用构造函数初始化Base,再进Base1初始化Base1

    //最后再进Test类初始化对象d,因为d是在派生类中创建的,所以要最后初始化,

    //Base和Base1初始化顺序按照继承顺序执行,并不按照派生类中初始化列表中的顺序进行

    d.Show();  

    //调用派生类中的函数Show(),在函数中_pri(派生类中的公有成员_pri)被赋值为10,

    //子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问

   d.Base::Show();  

    //调用基类Base中的Show(),因为都未赋值,所以显示的都为随机值

    d.Display();

    //_pri(派生类中的)显示为10,其他显示的地址,都相差4字节,说明在类中,开辟的地址是连续的

    d._dPub = 10;

    d.Show();

    //d._dPro = 20;    //保护成员在类外不可以访问

    system("pause");

    return 0;

}

运行结果:(运行环境是VS2013)

wKioL1cLTZyw5LZ2AAAybp3NeDg446.png



wKiom1cIoACDo1XoAAB81ZKuMk8489.png

总结:

1、基类的private成员在派生类中是不能被访问的。

2、如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。保护成员限定符是因继承才出现的。

3、public继承是一个接口继承,保持is-a原则,每个父类可用的成员对子类也可用,因为每个子类对象也都是一个父类对象。

4、protetced/private继承是一个实现继承,基类的部分成员并非完全成为子类接口的一部分,是 has-a 的关系原则,所以非特殊情况下不会使用这两种继承关系,在绝大多数的场景下使用的都是公有继承。

5、不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,基类的私有成员存在但是在子类中不可见(不能访问)。

6、使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。

7、在实际运用中一般使用都是public继承,极少场景下才会使用protetced/private继承.

1、私有成员只能在基类访问,在派生类和其他地方都不能访问 

2、保护成员在类外不可以访问

3、在派生类中初始化基类时,系统会按照继承的先后顺序依次调用相应的构造函数来初始化,而不是根据初始化列表中的顺序

1、在继承体系中基类和派生类是两个不同作用域。

2、子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问。(在子类成员函数中,可以使用 基类::基类成员 访问)--隐藏 --重定义

3、注意在实际中在继承体系里面最好不要定义同名的成员。


【继承关系中构造函数调用顺序】

wKioL1cIk5jwN5NOAAAscY_8knc587.png

【说明】

  1、基类没有缺省构造函数,派生类必须要在初始化列表中显式给出基类名和参数列表。

class Base

{

public:

   Base(int data)

  {  }

};

class Base1

{

public:

   Base1(int data)

   {  }

};

class Derive: public Base, public Base1

{

public:

    Derive()

      : Base1(10)

      , Base(20)


     {  }

};

     

  2、基类没有定义构造函数,则派生类也可以不用定义,全部使用缺省构造函数。

  3、基类定义了带有形参表构造函数,派生类就一定定义构造函数。


【继承关系中析构函数调用顺序】

wKiom1cIkuijKCwFAAAooEarDD4689.png

4、友元与继承及其赋值兼容:

class Base

{

public:

    friend void Display(Base b);

    Base(int data)

    {

        cout << data << endl;

        cout << "Base()" << this << endl;

       }

    ~Base()

    {

        cout << "~Base()" << endl;

    }

private:

    int _pri;

protected:

    int _pro;

public:

    int _pub;

};

class Derive :public Base

{

public:

    friend void Display(Base b);

    Derive()

        :Base(20)

    {

             cout << "Derive()" << this << endl;

    }

    ~Derive()

    {

        cout << "~Derive()" << endl;

    }

private:

    int _dPri;

protected:

    int _dPro;

public:

    int _dPub;

    int _pri;  

 //子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问

};

void Display(Base b)

{

    cout << b._pri << endl; 

    cout << b._pro << endl; 

    cout << b._pub << endl;

    Derive d;

    //cout << d._dPri << endl; 

    //友元关系不能继承,基类友元不能访问子类私有和保护成员

系统给出的错误提示: wKioL1cLTuvgyNkZAAAEfa8RUQc105.png

  //如果Display是基类Base的友元函数,则不能访问派生类的私有和保护成员

    //如果Display是派生类的友元函数,则可以访问

}

int main()

{

    Derive d;   //子类对象

    Base b(0);   //父类对象

    b = d;  //子类对象可以赋值给父类对象

    //d = b;   //父类对象不可以赋值给子类对象

    Base*pBase = &d;  //父类指针

    Derive *pd = (Derive*)&b;  //子类指针

    pBase = pd;  //父类的指针/引用可以指向子类对象

    //pd = pBase;    //子类的指针/引用不能指向父类对象 (可以通过强制类型转换实现)

    return 0;

}

系统给出的错误提示:

wKiom1cLTpjSpPFQAAAddUuz31g639.png

wKiom1cLTsHxDSV0AAAKF4IxS6w832.png

总结:

1、友元关系不能继承,基类友元不能访问子类私有和保护成员

2、子类对象可以赋值给父类对象

3、父类对象不可以赋值给子类对象

4、父类的指针/引用可以指向子类对象

5、子类的指针/引用不能指向父类对象 (可以通过强制类型转换实现)

6、基类定义了static成员,则整个继承体系里面只有一个这样的成员。


除了单继承,还有多继承和菱形继承,以下可区别它们之间的区别:

                              wKiom1cImtTjhiZkAAAWqsxA9Mg290.png    

                        wKiom1cImtWAhDZ9AAAU-kwWhf0253.png

               wKiom1cInM_CdaCOAAAeRTrpFZU333.png