继承
1.什么是继承
类的继承,是新的类从已有类那里得到已有的特性,从另一角度看,从已有类产生新类的过程就是类的派生。
原有的类称为基类或父类,产生的新类称为派生类或子类。
继承可以减少代码重复,避免造成数据不一致,便于软件维护。
2.派生类的定义
语法:
class 派生类名:继承方式 基类名1,继承方式 基类名2,……,继承方式 基类名n
{
派生类成员声明;
};
假设现有两个已定义的类cl1,cl2,先用新类cl3继承之,代码如下:
1 class cl3 :public cl1, private cl2 2 { 3 public: 4 getX(int x); 5 private: 6 int x, y; 7 8 };
该继承为多继承,public、private为继承方式关键词,分别表示公有继承和私有继承,因此还有以下要点:
①多继承与单继承。一个派生类,可以同时有多个基类,这种情况成为多继承,一个派生类只有一个直接基类的情况,成为单继承
②直接与间接基类。在类族中,直接参与派生出某类的基类称为直接基类,基类的基类甚至更高层的基类称为间接基类
③继承方式。继承方式关键字为:public,protected,private,分别表示公有继承、保护继承和私有继承,默认为私有继承(private)
④派生类成员。派生类成员是指除了从基类继承来的所有成员之外,新增加的数据和函数成员
3.派生类生成过程
面向对象的继承和派生机制,其主要的目的是实现代码的重用和扩充。
代码给出 【书P254】
1 class Account {//账户类 2 private: 3 std::string id;//账号 4 double balance;//余额 5 static double total;//所有账户的总金额 6 protected: 7 Account(const Date& date, const std::string &id); 8 void record(const Date& date, double amount, const std::string& id); 9 void errror(const std::string& msg)const; 10 public: 11 const std::string& getId()const { return id; } 12 double getBlance()const { return balance; } 13 static double getTotal() { return total;} 14 void show()const; 15 }; 16 17 class CreditAccount :public Account { 18 private: 19 Accmulator acc; 20 double credit; 21 double rate; 22 double fee; 23 double getDebt()const; 24 public: 25 //构造函数 26 CreditAccount(const Date& date, const std::string& id, double credit, double rate, double fee); 27 double getCredit()const; 28 double getRate()const; 29 double getFee()const; 30 double getAvailabeCredit(); 31 void deposit(const Date& date, double amount, const std::string& desc); 32 void settle(const Date& date); 33 void show()const; 34 };
由此总结,类的派生过程主要有以下步骤:
①吸收基类成员。第一步是将基类的成员全盘接收,在此,派生类CreditAccount继承了基类Account中除构造和构析函数之外
的所有非静态成员(静态成员不能被继承,相关实验在下文“访问”中给出)
②改造基类成员
对基类成员的改造分为两方面,一是基类成员的访问控制问题(相关实验在下文“访问”中给出),二是数据/函数成员的覆盖与隐藏
如果派生类声明了一个和某基类成员同名、参数相同的新成员,派生类的新成员就隐藏了外层同名成员。如给出代码中,派生类
CreditAccount中的show()函数就隐藏了Account中的同名函数
③添加新的成员
即根据实际情况的需要,给派生类添加适当的数据和函数成员来实现新增功能。如给出代码中的数据成员acc,credit,rate,fee等
4.访问
①公有继承
当类的继承方式为公有继承时,基类的公有成员和保护成员的访问属性在派生类中不变,而基类的私有成员不可直接访问
(即派生类中函数无法访问基类私有成员)。派生类新增成员之间可以直接访问。
代码给出 类【书P256-258】
标头.h
1 #pragma once 2 //#ifndef _POINT_H 3 //#define _POINT_H 4 #include<iostream> 5 using namespace std; 6 class Point { 7 public: 8 void initP(float xx=0, float yy=0) { 9 this->x=xx; 10 this->y=yy; 11 } 12 void Move(float xOff, float yOff) { 13 x += xOff; 14 y += yOff; 15 } 16 float getX() { 17 return x; 18 } 19 float GetY() { 20 return y; 21 } 22 private: 23 float x, y; 24 }; 25 //#endif
源文件
1 #include<iostream> 2 //#include<cmath> 3 #include"标头.h" 4 using namespace std; 5 /*class Point { 6 public: 7 void initP(float xx, float yy); 8 void Move(float xOff, float yOff) { 9 cout << x <<" "<< y; 10 } 11 float getX() { 12 return x; 13 } 14 float GetY() { 15 return y; 16 } 17 private: 18 float x, y; 19 }; 20 */ 21 class Rectangle :public Point { 22 public: 23 void initR(float x, float y, float w, float h) { 24 initP(x, y); 25 this->W=w; 26 this->H=h; 27 } 28 void move(float xOff, float yOff) { 29 Point::Move(xOff, yOff); 30 } 31 float GetH() { 32 return H; 33 } 34 float GetW() { 35 return W; 36 } 37 private: 38 float W, H; 39 }; 40 41 int main() { 42 Rectangle r1; 43 r1.initR(2, 3, 20, 10); 44 r1.Move(3, 2); 45 cout << r1.getX() <<" " << r1.GetY()<<" " << r1.GetW()<<" " << r1.GetH(); 46 return 0; 47 }
运行结果
(实验代码如下)
1 //公有继承实验 2 #include<iostream> 3 using namespace std; 4 class parent { //此为基类 5 public: 6 int getY() { 7 return y; 8 } 9 int x=1; 10 private: 11 int y=2; 12 }; 13 class child :public parent { //此为派生类 14 public: 15 int a=3; 16 private: 17 int b=4; 18 }; 19 20 int main() { 21 child c1; 22 parent p1; 23 cout << p1.getY() << endl; //调用基类函数 24 cout << c1.getY() << endl; //从派生类调用该函数 25 return 0; 26 }
运行结果(两函数均可执行):
②私有继承
私有继承与公有继承的区别在于权限设置不同。
将上面代码中的“public”改为"private",程序无法执行,下部框显示:
严重性 代码 说明 项目 文件 行 禁止显示状态
错误(活动) E0265 函数 "parent::getY" (已声明 所在行数:104) 不可访问 123 C:\Users\王鸽鸽\source\repos\123\123\源.cpp 122
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 C2247 “parent::getY”不可访问,因为“child”使用“private”从“parent”继承 123 C:\Users\王鸽鸽\source\repos\123\123\源.cpp 122
将第23行改为注释,程序可执行,因此验证了②的说法
③保护继承
保护继承中,基类的公有成员和保护成员都以保护成员的身份出现在派生类中,而基类的私有成员不可直接访问
1 //保护继承实验 2 2 #include<iostream> 3 3 using namespace std; 4 4 class parent { //此为基类 5 5 public: 6 6 int getY() { 7 7 return y; 8 8 } 9 9 int x=1; 10 10 private: 11 11 int y=2; 12 12 }; 13 13 class child :protected parent { //此为派生类 14 14 public: 15 15 int a=3; 16 16 private: 17 17 int b=4; 18 18 }; 19 19 20 20 int main() { 21 21 child c1; 22 22 parent p1; 23 int z; 25 23 cout << p1.getY() << endl; //调用基类函数 26 24 cout << c1.getY() << endl; //从派生类调用该函数,运行报错 27 25 return 0; 28 26 }
显然,基类的成员作为保护类型继承给派生类
5.派生类的构造与构析函数
如果对基类初始化时,需要调用基类的带有形参表的构造函数时,派生类就必须声明构造函数,提供一个将参数传递给基类构造函数的途径
如果需要析构的话,就要在派生类中声明新的析构函数,声明方法与非继承中完全相同
当析构函数函数体为空,它会隐含地调用派生类对象成员所在类的析构函数和调用基类的析构函数
关于执行的先后顺序,实验代码如下
1 #include <iostream> 2 using namespace std; 3 4 class Base { 5 public: 6 Base() { 7 cout << "基类构造函数" << endl; 8 } 9 10 ~Base() { 11 cout << "基类析构函数" << endl; 12 } 13 }; 14 15 class Derived : public Base { 16 public: 17 Derived() { 18 cout << "派生类构造函数" << endl; 19 } 20 21 ~Derived() { 22 cout << "派生类析构函数" << endl; 23 } 24 }; 25 26 int main() 27 { 28 Derived s; 29 }
运行结果
显然,当牵扯到继承与派生时,先构造基类,再构造派生类,先构析派生类,再构析基类