类的继承概述
继承性是面向对象程序设计的第二大特性,它允许在既有类的基础上创建新类,新类可以继承既有类的数据成员和成员函数,可以添加自己特有的数据成员和成员函数,还可以对既有类中的成员函数重新定义。利用类的继承和派生实现了更高层次的代码可重用性,符合现代软件开发的思想。
被继承的类叫做基类,继承出来的类叫做派生类
C++语言同时支持单一继承和多重继承。单一继承是指派生类只从一个基类继承而来;相应的,多重继承指派生类同时从两个或更多的基类继承而来。java只支持单一继承。
类的继承最大的作用即为代码的服用,不需要每次都重新写新的代码了。
C++ 类的继承有三种方式:
- 公有继承
- 私有继承
- 保护继承
派生类的对象同时也是一个基类对象,可以对基类对象进行的操作也可以对派生类的对象进行。
派生类可以在已有类的基础上面添加自己的数据和行为,甚至是修改基类方法的行为,但是不能删除基类的属性。
在只提供类方法的头文件和编译后代码,依然可以使用库中的类派生出新的类.
一个派生类能够继承父类的所有成员,不管是私有的还是共有的.但是继承下来的私有成员只能够用前面从父类继承下来的公有方法来访问. 具体的派生类的成员属性如下图:
继承过程
步骤1:首先根据实际情况创建一个基类
创建基类需要简洁和有意义,是一门很重要的思想。
步骤2:在已有基类的基础之上建立派生类
以共有派生为例子
1.派生类可以自己添加新的方法和数据。(在派生类中新写上去的就是添加的.)
2.派生类必须要自己新加一个新的构造函数。
派生类的定义格式如下:
class <派生类名>:[继承方式]<基类名1>,[继承方式]<基类名2>,...,[继承方式]<基类名n>
{
<派生类新增的数据成员和成员函数定义>
};
说明:
(1)定义派生类关键字可以是class或者是struct,两者区别是:用class定义派生类,默认的继承方式是private,用struct定义派生类,默认的继承方式为public。新增加的成员默认属性也是class对应private属性,struct对应public属性。
(2)基类不能被派生类继承的两类函数是构造函数和析构函数。
派生类的构造函数,
1、首先创建基类对象
2、派生类的构造函数通过成员初始化列表将基类的信息传递给基类构造函数。(这个分情况,可能调用基类的构造函数,默认构造函数和复制构造函数)
3、派生类的构造函数应初始化派生类新增的数据成员。
基类的私有部分也是派生类的一部分,但是只能通过基类的公有和保护方法来进行访问。访问权限也是很重要的。
基类和派生类的关系:
1、派生类可以使用基类的方法,这个方法不能是私有的。
2、基类指针可以在不进行显示转换的情况下指向派生类,基类引用可以在不显示转换的情况下,引用派生类对象(向上强制转换,不能将派生类的指针指向派生类)
继承方式举例:public, private 和 protected
class Base
{
public:
int pub_mem;
protected:
int pro_mem;
private:
int pri_mem;
};
class Pub_Derv : public Base
{
public:
void out_put_base_data()
{
cout << pub_mem << endl; //正确,public成员是公有的
cout << pro_mem << endl; //正确,基类中protected成员可以被派生类访问
cout << pri_mem << endl; //错误,private成员只能在所在类内使用
}
};
class Pro_Derv : protected Base
{
public:
void out_put_base_data()
{
cout << pub_mem << endl; //正确,public成员是公有的
cout << pro_mem << endl; //正确,基类中protected成员可以被派生类访问
cout << pri_mem << endl; //错误,private成员只能在所在类内使用
}
};
class Pri_Derv : private Base
{
public:
void out_put_base_data()
{
cout << pub_mem << endl; //正确,public成员是公有的
cout << pro_mem << endl; //正确,基类中protected成员可以被派生类访问
cout << pri_mem << endl; //错误,private成员只能在所在类内使用
}
};
int main(void)
{
Pub_Derv d1; //Pub_Derv是public方式继承Base的,所以在派生类中所有基类成员保持其原访问属性
d1.pub_mem = 1; //正确
d1.pro_mem = 2; //错误,在派生类中pro_mem的访问属性是protected
d1.pri_mem = 3; //错误,在派生类中pri_mem的访问属性是private
Pro_Derv d1;
d1.pub_mem = 1; //错误,在派生类中pub_mem的访问属性是protected
d1.pro_mem = 2; //错误,在派生类中pro_mem的访问属性是protected
d1.pri_mem = 3; //错误,在派生类中pri_mem的访问属性是private
Pri_Derv d2;
d2.pub_mem = 1; //错误,在派生类中pub_mem的访问属性是private
d2.pro_mem = 2; //错误,在派生类中pro_mem的访问属性是private
d2.pri_mem = 3; //错误,在派生类中pri_mem的访问属性是private
return 0;
}
从上面的代码执行结果可见,派生类的继承说明符的目的是控制派生类视同这对于基类成员的访问权限。若继承方式是public的,则成员将遵循其原有的在基类中的访问说明符;若继承方式是protected的,则基类的所有public成员都是protected的,此时只能是派生类的成员和友元可以访问这些些继承而来的public成员。若继承是private的,则在派生类中所有public、protected基类成员都是private的,同理,只有派生类的成员函数和友元才能访问这些继承而来的原先是public、protected的成员。
单一继承和多重继承举例
单一继承
//单一继承
#include"stdafx.h"
#include<iostream>
using namespace std;
class Other
{
public:
Other()
{
cout<<"constructing Other class"<<endl;
}
~Other()
{
cout<<"destructing Other class"<<endl;
}
};
class Base
{
public:
Base()
{
cout<<"constructing Base class"<<endl;
}
~Base()
{
cout<<"destructing Base class"<<endl;
}
};
class Derive:public Base
{
private:
Other ot;
public:
Derive()
{
cout<<"constructing Derive class"<<endl;
}
~Derive()
{
cout<<"destructing Derive class"<<endl;
}
};
int main()
{
Derive d;
return 0;
}
程序结果如下:
可以看到定义派生类对象时,构造函数的调用顺序:
a.先调用基类的构造函数
b.然后调用派生类对象成员所属类的构造函数(如果有对象成员)
c.最后调用派生类的构造函数
析构函数的调用顺序正好与构造函数调用顺序相反。
多重继承
#include"stdafx.h"
#include<iostream>
using namespace std;
class Grand
{
int g;
public:
Grand(int n):g(n)
{
cout<<"Constructor of class Grand g="<<g<<endl;
}
~Grand()
{
cout<<"Destructor of class Grand"<<endl;
}
};
class Father:public Grand
{
int f;
public:
Father(int n1,int n2):Grand(n2),f(n1)
{
cout<<"Constructor of class Father f="<<f<<endl;
}
~Father()
{
cout<<"Destructor of class Father"<<endl;
}
};
class Mother
{
int m;
public:
Mother(int n):m(n)
{
cout<<"Constructor of class Mother m="<<m<<endl;
}
~Mother()
{
cout<<"Destructor of class Mother"<<endl;
}
};
class Son:public Father,public Mother
{
int s;
public:
Son(int n1,int n2,int n3,int n4):Mother(n2),Father(n3,n4),s(n1)
{
cout<<"Constructor of class Son s="<<s<<endl;
}
~Son()
{
cout<<"Destructor of class Son"<<endl;
}
};
int main()
{
Son s(1,2,3,4);
return 0;
}
程序运行结果如下:
可以看到,与单一继承不同的是:在多重继承中,派生类有多个平行的基类,这些处于同一层次的基类构造函数的调用顺序,取决于声明派生类时所指定的各个基类的顺序,而与派生类构造函数的成员初始化列表中调用基类构造函数的顺序无关。