继承与派生(1)

来源:互联网 发布:vm共享文件夹 linux 编辑:程序博客网 时间:2024/06/05 02:58
  1. 类的继承是新类从已有类那里得到已有的特性,而从已有类产生新类的过程就是类的派生。原有的类称为基类或父类,产生的新类称为派生类或者子类。
  2. 派生类的定义
    C++中派生类的一般定义语法为:
    class 派生类名 : 继承方式 基类名1, 继承方式 基类名2, …..继承方式 基类名n
    {
    派生类成员声明;
    };
    一个派生类可以同时有多个基类,称为多继承,一个派生类只有一个直接基类的情况称为单继承。派生类成员是指除了从基类继承来的所有成员之外,新增加的数据和函数成员。
  3. 派生类生成过程
    a. 吸收基类成员:派生类包含了基类中除了构造函数和析构函数外的所有成员。
    b. 改造基类成员:如果派生类声明了一个和某一基类成员同名的新成员(如果是成员函数,参数列表也要相同,参数不同的情况属于重载),派生类的新成员就隐藏了外层同名成员。(着重学习不同继承方式下的基类成员的访问控制问题)
    c . 添加新的成员:因为在派生过程中基类的构造函数和析构函数是不能被继承的,要实现一些特殊的初始化和扫尾工作,就需要在派生类中加入新的构造函数和析构函数 。(重点是构造函数与析构函数)
  4. 访问控制
    从基类继承的成员,其访问属性由继承方式控制。
    基类成员有public(公有)、private(私有)、protected(保护)三中访问属性。基类自身成员可以对基类的任何一个其他成员进行访问,但是通过基类的对象,就只能访问该类的公有成员。
    相对应的类的继承方式也有public(公有继承)、private(私有继承)、protected(保护继承)三种。不同的继承方式导致原来具有不同访问属性的基类成员在派生类的访问属性也有所不同。这里的访问有两个方面:一是派生类中的新增成员访问从基类继承的成员,二是在派生类外部通过派生类的对象访问从基类继承的成员。
    1)公有继承
    当类的继承方式为公有继承时,基类的公有成员和保护成员在派生类中不变,但基类的私有成员不可直接访问。即基类的公有成员和保护成员在派生类中访问属性不变,仍作为派生类的公有成员和保护成员,派生类的其他成员可以直接访问他们,在类族之外只能通过派生类的对象访问从基类继承的公有成员,但无论是派生类的成员还是派生类的对象都无法直接访问基类的私有成员。
    2)保护继承
    保护继承中,基类的公有成员和保护成员都以保护成员的身份出现在派生类中,而基类的私有成员不可直接访问。所以,派生类的其他成员可以直接访问从基类继承来的公有成员和保护成员,但是在类外通过派生类的对象无法直接访问它们。
    3)私有继承
    当以私有继承的方式继承基类时,基类中的公有成员和保护成员都以私有成员身份出现在派生类中,而基类的私有成员在派生类中不可直接访问。即基类的公有成员和保护成员继承后被作为派生类的私有成员,派生类的其他成员可以直接访问它们,但在类外通过派生类的对象无法直接访问它们。无论是派生类的成员还是派生类的对象都不能访问基类的私有成员。
    以上所述可以用下面这张表来表示:(左边一列表示基类中的成员访问属性)
    这里写图片描述
    下面用简单的代码来说明:
class A    //基类{public:    A(int i=0){}    int m_k;    void fn(){cout<<"A"<<endl;}protected:    int m_j;private:    int m_i;};class B:public A   //公有继承{public:    void print()    {        cout<<"B print"<<endl;        m_i = 2;  // m_i是父类的私有成员  不可访问        m_j = 3;        m_k = 4;    }    void fn()    {        cout<<"B fn()"<<endl;    }private:    int m_m;};class C:protected A    //保护继承{public:    void print()    {        m_i = 7;    //error  m_i是基类的私有成员   不可访问        m_j = 8;        m_k = 9;    }}class D:private A   //私有继承{public:    void print()    {        m_i = 3;  //error   m_i是基类的私有成员  不可访问        m_j = 1;        m_k = 0;    }}

这里要说说protected 继承和private继承的区别:
如果只是派生一层,那么二者没有区别;但要是继续派生的话private继承将在下层无法 访问。

接着向下看:

class A{public:    A(int i):m_i(i){cout<<"A"<<i<<endl;}    ~A(){cout<<"~A"<<endl;}private:    int m_i;};class B:public A{public:    B(int i=0):m_j(i){cout<<"B"<<i<<endl;}    ~B(){cout<<"~B"<<endl;}private:    int m_j;};void main(){    B b(9);}

B类公有继承了A类,但是程序运行会报错
这里写图片描述
但如果将A类中的构造函数改为带默认值的构造函数:
A(int i=0):m_i(i){cout<<"A"<<i<<endl;}
程序就可以运行:
这里写图片描述
在派生类的构造函数中显示调用基类的构造函数也可以解决问题:
B(int i=0):A(6),m_j(i){cout<<"B"<<i<<endl;}
运行结果如下:
这里写图片描述
如若基类带有无参构造函数也是可以的:
A(){}
运行结果:
这里写图片描述
这也就是说如果子类的构造函数没有显示调用基类的构造函数,则基类必须有无参构造函数或者带默认值的构造函数,并且在调用子类构造函数前,先调用基类的构造函数给派生过来的所有基类成员进行初始化。