21、C++类的继承

来源:互联网 发布:sql截掉字符串 编辑:程序博客网 时间:2024/06/06 23:18

C++中类的继承

继承是面向对象程序设计的一个重要特征,它允许在已有的基础上创建新的类,

新类可以从一个或多个已有类中继承函数和数据,而且可以重新定义或加进新的数据和

函数,从而形成类的层次或等级。其中已有类称为基类或父类,在它基础上建立的

新类称为派生类或子类。

一、继承方式以及类中的访问修饰符

1、类中的访问修饰符:

指定了类外对象和子类访问类内成员的权限。

public :类内和对象均可以使用,派生类也可以访问。

private:只有类内可以使用。(成员函数的本类的对象也可以访问),在派生类

中不可访问。

protected:类内可以使用,以及派生类中可以访问。

2、继承中的访问修饰符:(继承方式)

指定了派生类成员以及类外对象对于从基类继承来的成员的访问权限。

public:在派生类中,所有基类的成员的访问属性保持原来不变。

protected:在派生类中,所有基类public 成员在派生类中都变成protected

成员,基类的private protected成员的访问权限仍然保持不变

private:在派生类,所有基类的成员在派生类中都变成了private访问权限。

注:对于公有继承,因为派生类支持基类的所有公共属性和方法,

所以公有继承也被称为接口声明。

而私有继承和保护继承只是利用属性和方法,所以也被称为实现继承。

二、派生类的声明

基本语法:

class 派生类名:: [继承方式] 基类名1,[继承方式] 基类名2

派生类新增的数据成员和成员函数。

};

注:[ ]表示可加可不加,默认private继承,可多继承。

三、基类成员在派生类中的访问属性

public:在派生类中,所有基类的成员的访问属性保持原来不变。

protected:在派生类中,所有基类public 成员在派生类中都变成protected

成员,基类的private protected成员的访问权限仍然保持不变

private:在派生类,所有基类的成员在派生类中都变成了private访问权限。

注:1、所有基类中的私有成员都不可以访问。其它均可访问。

2、子类对象对基类成员的访问权限,因为基类的成员已经被派生类继承了,那么

继承以后的访问权限决定了子类对象对其的访问。

四、派生类的构造函数和析构函数

1、派生类的构造函数

基本语法:

派生类构造函数名(形参表):基类构造函数(形参表),. . .,派生类成员的初始化

构造函数体

调用顺序:基类的构造函数,派生类成员的初始化,派生类的构造函数

含有对象成员的派生类的构造函数:

派生类名(参数总表):基类名(参数表),. . .,对象成员1(参数表),. . . 

{

}

调用顺序:基类的构造函数,内嵌对象成员的构造函数,派生类的构造函数。

2、派生类的析构函数

只需要对本身的成员进行清理,而不用理会基类中的成员,基类的清理工作仍然由

基类的析构函数负责。

调用顺序:析构函数的调用顺序与构造函数正好相反。

五、调整基类成员在派生类中访问属性

1、指定访问基类中的成员(如:子类中有与基类中同名的成员)

基类名::成员名;

如果是成员函数,需要用到 (  ) 和参数

2、访问声明

一般访问声明机制可以在私有派生类中个别调整从基类继承下来的成员访问权限。从而

使外界可以通过派生类的界面直接访问基类的某些成员,同时也不影响其他基类成员

的封闭性。

基本语法: 基类名::成员名;

或者 using  基类名::成员名;

如果是成员函数,只需要用到函数名,而不需要用到 ( ) 和参数。

注:可以将无论何种继承时,将部分基类中的成员,保持原有的或者提高访问权限。

也可以降低,但是不可以访问声明私有成员。

六、虚基类

引入虚基类的原因:如果有一个类有多个直接基类,而这些直接基类又有一个共同的基

类,则最低层的派生类会保留这个间接的共同基类数据成员的多份

同名成员,在访问这些同名的成员时,必须在派生类对象名后增加

直接基类名,使其惟一标识一个成员,以免产生二义性。

为了摆脱这种加直接基类名,引入了虚基类。

作用:虚继承基类,无论有多少个派生类虚拟继承这个基类,都只是给了每一个

派生类一个指针,指向这个基类的这份数据,就不会产生多份数据。

基本语法:

在继承方式前面加上virtual.

七、虚基类的初始化

在使用了虚继承以后。如果在虚基类中没有定义默认形式的构造函数,那么在整个继承

结构中,所有直接和间接派生类都必须在构造函数的成员初始化列表中列出对虚基类

构造函数的调用。但是真正起作用的是最低层的派生类。编译器会忽视掉中间的基类

构造函数的调用。

注:一个类可以是一些类的虚拟基类,也可以是一些类的非虚基类。

调用顺序:虚基类的构造函数优先于同级别的非虚基类的构造函数

八、派生类对象的内存布局

  派生类对象

基类1成员

基类2成员

派生类成员

将子类对象转换为基类对象时,是将子类对象内存中划出指定初始地址的,指定大小的基

类的内存。

九、基类与派生类对象之间的赋值兼容关系(仅限公有继承)

通过公有继承,派生类保留了基类中除构造函数、析构函数之外的所有成员

,并保持了原有的访问权限。因此公有派生类具有基类的全部功能。凡是基

类能够实现的功能,公有派生类都能实现。

1、派生类对象可以向基类对象赋值。

如:

Base b;

Drived d;

b=d;

2、派生类对象可以初始化基类对象的引用

如:

Base b;

Derived d;

Base &br=d;

3、派生类对象的地址可以赋给指向基类对象的指针

Derived d;

Base  *bp=&d;

4、如果函数的形参是基类对象或基类对象的引用,在调用函数时

可以用派生类对象作为实参。

注:

1、声明为指向基类对象的指针可以指向它的公有派生类对象,但不可以是

私有继承的派生类对象。

2、允许将一个声明为指向基类的指针指向其公有派生类的对象,但是不

能将一个声明为指向派生类对象的指针指向基类的一个对象。

3、基类的指针和引用,如果指向派生类对象,那么只关心派生类从基类继承过来的成员和函数。对派生类中新加的成员忽略。

测试程序:

#include <iostream>using namespace std;class Base{private:    int count;    int pri_data;protected:    int ptd_data;public:    int pub_data;  Base(int c,int prd,int ptd,int pud):count(c),pri_data(prd),ptd_data(ptd),pub_data(pud)  {        cout<<"调用Base类的构造函数!"<<endl;  }  void print()  {      cout<<"调用Base类的print():count="<<count<<",pri_data="<<pri_data      <<",ptd_data="<<ptd_data<<",pub_data="<<pub_data<<endl;  }};class Derived:public Base  //公有继承,所有基类成员的访问权限都保持不变{private:    int count;    int d_data;    Base::pub_data;//访问声明,将基类的公有成员声明为私有成员public:    Derived(int c,int d,int prd,int ptd,int pud):Base(c,prd,ptd,pud),count(c-1),d_data(d-1)    {        cout<<"调用Derived类的构造函数!"<<endl;    }    //Base::pri_data;错误,只能访问声明非私有成员,    void print()    {        Base::print();//调用基类的函数,        cout<<"调用Derived类的print()函数,Derived::count="<<count<<",Derived::d_data="<<d_data<<endl;    }};class Derived2:protected Base{private:    int count;    int d_data;public:    Derived2(int c,int d,int prd,int ptd,int pud):Base(c,prd,ptd,pud),count(c-1),d_data(d-1)    {        cout<<"调用Derived2类的构造函数!"<<endl;    }    Base::print;//访问声明    Base::ptd_data;//这样就成了公有成员。可以在外部使用对象访问。    void print()    {        Base::print();//调用基类的函数,        cout<<"调用Derived2类的print()函数,Derived2::count="<<count<<",Derived2::d_data="<<d_data<<endl;    }};class Derived3:private Base{private:    int count;    int d_data;public:    Derived3(int c,int d,int prd,int ptd,int pud):Base(c,prd,ptd,pud),count(c-1),d_data(d-1)    {        cout<<"调用Derived3类的构造函数!"<<endl;    }    Base::print;//访问声明    Base::ptd_data;//因为访问声明在public修饰下,这样就成了公有成员。可以在外部使用对象访问。     //Base::pri_data;错误,只能访问声明非私有成员,    void print()    {        Base::print();//调用基类的函数,        cout<<"调用Derived3类的print()函数,Derived3::count="<<count<<",Derived3::d_data="<<d_data<<endl;    }};int main(){    Derived d1(1,2,3,4,5);    //d1.pri_data;//错误,私有成员    //d1.pub_data;//错误,公有继承,但是在在派生类中访问声明成了私有成员所以不可以访问。    d1.print();    Derived2 d2(1,2,3,4,5);    //d2.pub_data;错误,公有成员,被保护继承,变成了保护成员    d2.ptd_data;//基类原有保护访问的成员被访问声明为派生类的public成员。    d2.print();    Derived3 d3(1,2,3,4,5);    //d3.pub_data;错误,公有成员,被私有继承,变成了保护成员    d3.print();    d3.ptd_data;//正确,虽然私有继承了,不过在派生类中,将其访问声明成了public成员。    Base b(1,2,3,4);    b=d1;    Base &bd1=d1;    d1.print();//    Base &bd2=d2;错误,只能指向公有继承。//    Base &bd3=d3;    return 0;}


输出结果:

调用Base类的构造函数!

调用Derived类的构造函数!

调用Base类的print():count=1,pri_data=3,ptd_data=4,pub_data=5

调用Derived类的print()函数,Derived::count=0,Derived::d_data=1

调用Base类的构造函数!

调用Derived2类的构造函数!

调用Base类的print():count=1,pri_data=3,ptd_data=4,pub_data=5

调用Derived2类的print()函数,Derived2::count=0,Derived2::d_data=1

调用Base类的构造函数!

调用Derived3类的构造函数!

调用Base类的print():count=1,pri_data=3,ptd_data=4,pub_data=5

调用Derived3类的print()函数,Derived3::count=0,Derived3::d_data=1

调用Base类的构造函数!

调用Base类的print():count=1,pri_data=3,ptd_data=4,pub_data=5

调用Derived类的print()函数,Derived::count=0,Derived::d_data=1

Process returned 0 (0x0)   execution time : 0.240 s

Press any key to continue.


原创粉丝点击