C++:基类和派生类
4.1 派生类的声明
继承实例如下: class Person{ //声明基类Person public: void print() { cout<<"name:"<<name<<endl; cout<<"age:"<<age<<endl; cout<<"sex:"<<sex<<endl; } protected: string name; int age; char sex; }; class Employee:public Person{ //声明派生类Employee公有继承了基类Person public: void print1() //新增成员函数 { print(); cout<<"department:"<<department<<endl; cout<<"salary:"<<salary<<endl; } private: string department; //新增数据成员 int salary; //新增数据成员 };
声明一个派生类的一般格式是:
Class 派生类 : [继承方式] 基类名{
派生类新增加的数据成员和成员函数
};
说明: 基类名为声明的父类,派生类为子类
继承方式分三种:public、private、protected
4.1.3 派生类的构成
(1)派生类从基类接收成员
在C++的类继承中,派生类把基类的全部成员函数(除了构造函数和析构函数)接收过来
(2)调整从基类接收的成员
一方面改变基类成员在派生类中的访问属性,主要通过声明时的继承方式来控制;
另一面派生类可以对基类中的函数进行重定义,即覆盖基类中的同名函数。
(3)在派生类中新增成员
新增的成员可以是数据成员,也可以是成员函数
注意:基类的构造函数和析构函数不能被继承,一般需要派生类声明自己的构造函数和析构函数。
4.1.4 基类成员在派生类中的访问属性
派生类可以继承除了构造函数与析构函数之外的成员,但是这些成员的访问属性在派生过程中
是可以调整的。从基类继承来的成员在派生类中的访问属性是由继承方式控制的。
类的继承方式有public公有继承、protected保护继承、private私有继承三种。不同的继承方式
导致不同访问属性的基类成员在派生类在派生类中的访问属性也有所不同。
在派生类中,从基类继承来的成员可以按访问属性划分为四种:不可直接访问、公有public、
保护protected、私有private。
表4.1 基类成员在派生类中的访问属性
————————————————————————————————————————————————
基类中的成员| 在公有派生类中的访问属性| 在私有派生类中的访问属性 | 在保护派生类中的访问属性
————————————————————————————————————————————————
私有成员 | 不可直接访问 | 不可直接访问 | 不可直接访问
公有成员 | 公有 | 私有 | 保护
保护成员 | 保 | 私有 | 保护
————————————————————————————————————————————————
从表4.1中可以归纳出以下几点
(1) 基类中的私有成员。
无论哪种继承方式,基类中的私有成员不允许派生类继承,即在派生类中是不可直接访问的。
(2) 基类中的公有成员
a.当类的继承方式为公有继承时,基类中的所有公有成员在派生类中仍以公有成员的身份出现。
b.当类的继承方式为私有继承时,基类中的所有公有成员在派生类中仍以私有成员的身份出现
c.当类的继承方式为保护继承时,基类中的所有公有成员在派生类中仍以保护成员的身份出现。
(3)基类中保护成员。
a.当类的继承方式为公有继承时,基类中的所有公有成员在派生类中仍以保护成员的身份出现。
b.当类的继承方式为私有继承时,基类中的所有公有成员在派生类中仍以私有成员的身份出现。
c.当类的继承方式为保护继承时,基类中的所有公有成员在派生类中仍以保护成员的身份出现。
4.1.5 派生类对基类成员的访问规则
基类的成员可以有public、protected、private三种访问属性,基类的成员函数可以访问基类中其它
成员,但是在基类外通过基类的对象,就只能访问基类的公有成员。
同样,派生类的成员也可以有public、protected、private三种访问属性,派生类的成员函数可以访问
派生类中自己增加的成员,但是在派生类外通过基类的对象,就只能访问该派生类的公有成员
。
派生类对基类成员的访问形式主要有以下两种:
(1)内部访问。由派生类中新增的成员函数对从基类继承来的成员的访问。
(2)对象访问。在派生类外部,同过派生类的对象对从基类继承来的成员的访问。
表4.2 私有继承的访问规则(private)
-----------------------------------------------------------------
基类中的成员 | 稀有成员 | 共有成员 |保护成员
-----------------------------------------------------------------
内部访问 | 不可访问 | 可访问 | 可访问
对象访问 | 不可访问 | 不可访问 | 不可访问
-----------------------------------------------------------------
//例4.1私有继承的访问规则举例1
#include<iostream> using namespace std; class Base{ //声明基类 public: void setx(int n) //正确,成员函数setx可以访问本类中的私有成员x { x = n; } void showx() //正确,成员函数showx可以访问本类中的私有成员x { cout<<x<<endl; } private: int x; }; class Derived:private Base{ //声明基类Base的私有派生类Derived public: void setxy(int n,int m) { setx(n); //正确,基类的setx函数在派生类中为私有成员,派生类中的成员函数可以访问 y = m; //正确,成员函数setxy可以访问本类中的私有成员y } void showxy() { //cout<<x; //错误,派生类中的成员函数不能直接访问基类中的私有成员 showx(); //正确,基类的showx函数在派生类中为私有成员,派生类中的成员函数可以访问 cout<<y<<endl; //正确,成员函数showxy可以直接访问本类中的私有成员y } private: int y; }; int main() { Derived obj; //obj.setx(10); //错误,setx在派生类中为私有成员,派生类对象不能直接访问。 //obj.showx(); //错误,showx在派生类中为私有成员,派生类对象不能直接访问。 obj.setxy(20,30); //正确,setxy在本类Derived中为公有成员,派生类对象能直接访问。 obj.showxy(); //正确,showxy在本类Derived中为公有成员,派生类对象能直接访问 return 0; } /* 说明:可见基类中的私有成员既不能被派生类的对象访问,也不能被派生类中的成员函数访问。即不可访问成员, 因此,在设计基类时,总要为它的私有数据提供公有成员函数,如在本例的成员函数showx等,以便使派 生类可以间接访问这些成员。 */
//私有继承的访问规则举例2
#include<iostream> using namespace std; class Base{ //声明基类Base public: void seta(int sa) //正确,成员函数seta可以访问本类中的保护成员a { a = sa; } void showa() { cout<<"a="<<a<<endl; //正确,成员函数showa可以访问本类中的保护成员a } protected: int a; }; class Derive1:private Base{ //声明基类Base的私有派生类Derive1 public: void setab(int sa,int sb) { a = sa; //正确,a在派生类中为私有成员,派生类成员函数可以访问 b = sb; //正确,b在派生类中为保护成员,派生类成员函数可以访问 } void showab() { showa(); //cout<<"a="<<a<<endl; //正确,a在派生类中为私有成员,派生类成员函数可以访问 cout<<"b="<<b<<endl; //正确,a在派生类中为保护成员,派生类成员函数可以访问 } protected: int b; }; class Derive2:private Derive1{ //声明类Derive1的私有派生类Derive2 public: void setabc(int sa,int sb,int sc) { setab(sa,sb); //正确,setab函数在派生类Derive2中为私有成员,成员函数setabc可以访问 c = sc; } void showabc() { showab(); //正确,showab函数在派生类Derive2中为私有成员,成员函数showabc可以访问 //cout<<"a="<<a<<endl; //错误,a在类Derive2中为不可直接访问成员 //cout<<"b="<<b<<endl; //正确,b在类Derive2中为私有成员 cout<<"c="<<c<<endl; //正确,c在类Derive2中为私有成员 } private: int c; }; int main() { Base op1; op1.seta(1); op1.showa(); Derive1 op2; op2.setab(2,3); op2.showab(); Derive2 op3; op3.setabc(4,5,6); op3.showabc(); return 0; } /* 说明:经过了私有继承后,所有基类中的成员都成为了派生类的私有成员或不可直接访问的 成员,如果进一步派生的话,基类的全部成员都无法在新的派生类中被访问。因此, 私有继承之后,基类的成员无法在以后的派生类中在发挥作用,实际是相当于中止了 基类功能的继承派生,出于这种原因,私有继承的实际应用很少。 */
表4.2 保护继承的访问规则(protected)
-----------------------------------------------------------------
基类中的成员 | 稀有成员 | 共有成员 |保护成员
-----------------------------------------------------------------
内部访问 | 不可访问 | 可访问 | 可访问
对象访问 | 不可访问 | 可访问 | 不可访问
-----------------------------------------------------------------
//例 4.4 保护继承的访问规则
#include<iostream> using namespace std; class Base{ public: int z; void setx(int i) { x = i; } int getx() { return x; } private: int x; protected: int y; }; class Derived:protected Base{ public: int p; void setall(int a,int b,int c,int d,int e,int f ); void showall(); private: int m; protected: int n; }; void Derived::setall(int a,int b,int c,int d,int e,int f) { //x = a;//错误,在派生类Derived中,x为不可直接访问成员,但是可以通过成员函数间接访问 setx(a); y = b; //正确,在派生类Derived中,Y仍是保护成员,派生类成员函数能访问它 z = c; //正确,在派生类Derived中,Y仍是保护成员,派生类成员函数能访问它 m = d; n = e; p = f; } void Derived::showall() { //cout<<"x="<<x<<endl; //错误,在派生类Derived中,x为不可直接访问成员 cout<<"x="<<getx()<<endl;//正确,函数getx在派生类Derived中为保护成员,派生类成员函数可以访问 cout<<"y="<<y<<endl; //正确,y在派生类Derived中为保护成员,派生类成员函数可以访问 cout<<"z="<<z<<endl; //正确,z在派生类Derived中为保护成员,派生类成员函数可以访问 cout<<"m="<<y<<endl; //正确,m在派生类Derived中为私有成员,派生类成员函数可以访问 cout<<"n="<<n<<endl; //正确,n在派生类Derived中为保护成员,派生类成员函数可以访问 } int main() { Derived obj; obj.setall(1,2,3,4,5,6); obj.showall(); //cout<<"y="<<obj.y<<endl; //错误,y为派生类Derived的保护成员,派生类对象不能直接访问它 cout<<"p="<<obj.p<<endl; //正确,p为派生类Derived的公有成员,派生类对象可以直接访问它 return 0; } /* 说明:例中的派生类Derived有基类Base保护派生出来,所以基类Base中的私有数据成员x在保护派生类 Derived中是不可直接访问的,因此派生类成员函数setall和showall不能访问它。基类Base中的 保护数据成员y在保护派生类Derived中仍是保护成员,因此派生类成员函数setall和showall能够 访问它,但是派生类Derived的对象obj不能访问它。派生类Derived的数据成员p是公有成员,所以 派生类Derived的对宪法obj可以访问它。 */
表4.2 公有继承的访问规则(public)
-----------------------------------------------------------------
基类中的成员 | 稀有成员 | 共有成员 |保护成员
-----------------------------------------------------------------
内部访问 | 不可访问 | 可访问 | 可访问
对象访问 | 不可访问 | 可访问 | 不可访问
-----------------------------------------------------------------
//例4.3 公有继承的访问规则
#include<iostream> using namespace std; class Base{ public: void setxy(int m,int n) { x = m; y = n; } void showxy() { cout<<"x="<<x<<endl; cout<<"y="<<y<<endl; } private: int x; protected: int y; }; class Derived:public Base{ //声明基类Base的公有继承类Derived public: void setxyz(int m,int n,int l) { setxy(m,n); //函数setxy在派生类中是public成员,派生类成员函数可以访问 z = l; } void showxyz() { //cout<<"x="<<x<<endl; //错误,x在类Derived中为不可直接访问成员 //showxy(); //函数showxy在派生类中是public成员,派生类成员函数可以访问 cout<<"y="<<y<<endl; //正确,y在类Derived中仍为protected成员,派生类成员函数可以访问 cout<<"z="<<z<<endl; } private: int z; }; int main() { Derived obj; obj.setxyz(30,40,50); obj.showxy();//正确,函数showxy在类Derived中为公有成员,派生类对象也可以直接访问 //obj.y=60; //错误,y在类Derived中仍为protected成员,派生类对象不可以访问 obj.showxyz(); return 0; } /* 说明:例中类Derievd有类Base公有派生出来,所以类Base中的两个公有成员函数setxy和showxy在 公有派生类中仍是公有成员。因此,它们可以分别被派生类的成员函数showxyz和派生类对象 obj直接访问。基类中数据成员x是私有的,它在派生类中不能直接访问的,所以在成员函数 showxyz中对x的访问是错误的。基类Base中的数据成员y是保护成员,它在公有派生类中仍是 保护成员,所以在派生类成员函数showxyz中对y的访问是正确的,但是派生类的对象不能访问。 */