C++笔记——继承与派生

1、继承和派生的概念

      继承:在定义一个新的类B时,如果该类与某个已有的类A相似(指的是B拥有A的全部特点),那么就可以把A作为一个基类,而把B作为基类的一个 派生类( 也称子类)

  • 派生类是通过对基类进行修改和扩充得到的。在派生类中,可以扩充新的成员变量和成员函数。
  • 派生类一经定义后,可以独立使用,不依赖于基类。
  • 派生类拥有基类的全部成员函数和成员变量,不论是private、protected、public 。
  • 在派生类的各个成员函数中,不能访问基类中的private成员。

2、派生类对象的内存空间

      派生类对象的体积,等于基类对象的体积,再加上派生类对象自己的成员变量的体积。在派生类对象中,包含着基类对象,而且基类对象的存储位置位于派生类对象新增的成员变量之前。

   

3、继承关系和复合关系

(1)继承:“是”关系。

  • 基类A,B是基类A的派生类。
  • 逻辑上要求:“一个B对象也是一个A对象”。

(2)复合:“有”关系。

  • 类C中“有”成员变量k,k是类D的对象,则C和D是复合关系
  • 一般逻辑上要求:“D对象是C对象的固有属性或组成部分”。

4、覆盖

     派生类可以定义一个和基类成员同名的成员,这叫覆盖。

     在派生类中访问这类成员时,缺省的情况是访问派生类中定义的成员。要在派生类中访问由基类定义的同名成员时,要使用作用域符号::。

5、存取权限说明符

(1)基类的private成员:可以被下列函数访问

  • – 基类的成员函数
  • – 基类的友员函数

(2)基类的public成员:可以被下列函数访问

  • – 基类的成员函数
  • – 基类的友员函数
  • – 派生类的成员函数
  • – 派生类的友员函数
  • – 其他的函数

(3)基类的protected成员:可以被下列函数访问

  • – 基类的成员函数
  • – 基类的友员函数
  • – 派生类的成员函数可以访问当前对象的基类的保护成员
class Father {
    private: int nPrivate;         // 私有成员
    public: int nPublic;           // 公有成员
    protected: int nProtected;     //  保护成员
};
class Son :public Father{
    void AccessFather () {
        nPublic = 1;        // ok;
        nPrivate = 1;       // wrong
        nProtected = 1;     // OK ,访问从基类继承的protected 成员
        Son f;
        f.nProtected = 1;  //wrong,f不是当前对象
    }
}

6、派生类的构造函数

(1)在创建派生类的对象时,需要调用基类的构造函数:初始化派生类对象中从基类继承的成员。在执行一个派生类的构造函数之前,总是先执行基类的构造函数。
(2) 调用基类构造函数的两种方式

  • – 显式方式:在派生类的构造函数中,为基类的构造函数提供参数. derived::derived(arg_derived-list):base(arg_base-list)
  • – 隐式方式:在派生类的构造函数中,省略基类构造函数时,派生类的构造函数则自动调用基类的默认构造函数.

(3)派生类的析构函数被执行时,执行完派生类的析构函数后,自动调用基类的析构函数。

class Bug {
    private :
        int nLegs; int nColor;
    public:
        int nType;
        Bug ( int legs, int color);
        void PrintBug (){ };
};
class FlyBug: public Bug {    // FlyBug 是Bug 的派生类

        int nWings;
    public:
        FlyBug( int legs,int color, int wings);
};
// 派生类的构造函数
Bug::Bug( int legs, int color){
    nLegs = legs;
    nColor = color;
}
// 错误的FlyBug 构造函数
FlyBug::FlyBug ( int legs,int color, int wings){
    nLegs = legs;     //  不能访问
    nColor = color;   //  不能访问
    nType = 1;        // ok
    nWings = wings;
}
// 正确的FlyBug 构造函数:
FlyBug::FlyBug ( int legs, int color, int wings):Bug( legs, color){
    nWings = wings;
}

(4)封闭派生类对象的构造函数执行顺序

  • 先执行基类的构造函数,用以初始化派生类对象中从基类继承的成员;
  • 再执行成员对象类的构造函数,用以初始化派生类对象中成员对象。
  • 最后执行派生类自己的构造函数

(5)封闭派生类对象消亡时析构函数的执行顺序

  • 先执行派生类自己的析构函数
  • 再依次执行各成员对象类的析构函数
  • 最后执行基类的析构函数

7、public继承的赋值兼容规则

class base { };
class derived : public base { };
base b;
derived d;

(1)派生类的对象可以赋值给基类对象
        b = d;
(2)派生类对象可以初始化基类引用
        base & br = d;

(3)派生类对象的地址可以赋值给基类指针
        base * pb = & d;
   注:

  • 如果派生方式是 private或protected,则上述三条不可行。
  • protected继承时,基类的public成员和protected成员成为派生类的protected成员。
  • private继承时,基类的public成员成为派生类的private成员,基类的protected成员成为派生类的不可访问成员。
  • protected和private继承不是“是”的关系。

8、基类与派生类的指针强制转换

(1)公有派生的情况下,派生类对象的指针可以直接赋值给基类指针
                  Base * ptrBase = &objDerived;
         ptrBase指向的是一个Derived类的对象;*ptrBase可以看作一个Base类的对象,访问它的public成员直接通过ptrBase即可
        ,但不能通过ptrBase访问objDerived对象中属于Derived类而不属于Base类的成员

(2) 即便基类指针指向的是一个派生类的对象,也不能通过基类指针访问基类没有,而派生类中有的成员。
(3)通过强制指针类型转换,可以把ptrBase转换成Derived类的指针
                Base * ptrBase = &objDerived;
                Derived *ptrDerived = (Derived * ) ptrBase;
         程序员要保证ptrBase指向的是一个Derived类的对象,否则很容易会出错。

9、直接基类与间接基类

       baseA->DerivedB->C->....

   在声明派生类时,只需要列出它的直接基类
   – 派生类沿着类的层次自动向上继承它的间接基类
   – 派生类的成员包括
         • 派生类自己定义的成员
         • 直接基类中的所有成员
         • 所有间接基类的全部成员

#include <iostream>
using namespace std;
class Base {
    public:
        int n;
        Base(int i):n(i) {
            cout << "Base " << n << " constructed"<< endl;
        }
        ~Base() {
            cout << "Base " << n << " destructed"<< endl;
        }
};
class Derived:public Base{
    public:
        Derived(int i):Base(i) {
            cout << "Derived constructed" << endl;
        }
        ~Derived() {
            cout << "Derived destructed" << endl;
        }
};
class MoreDerived:public Derived {
        public:
            MoreDerived():Derived(4) {
                cout << "More Derived constructed" << endl;
            }
            ~MoreDerived() {
                cout << "More Derived destructed" << endl;
            }
};
int main(){
    MoreDerived Obj;
    return 0;
}
输出结果:
Base 4 constructed
Derived constructed
More Derived constructed
More Derived destructed
Derived destructed
Base 4 destructed

猜你喜欢

转载自blog.csdn.net/wys7541/article/details/81514328
今日推荐