第四次作业
一、 类的继承与派生基本概念
1. 概念:(继承和派生是同一过程从不同角度看)
① 继承:是新的类从已有类那里得到已有的特性。
② 派生:从已有类的基础上新增自己的特性而产生新类的过程。
2.
被继承的已有类成为基类(或父类);
派生出的新类成为派生类(或子类);
直接参与派生出某类的基类称为直接基类;
基类的基类甚至更高层的基类称为间接基类。(多级派生,生成类族)
3. 目的:
① 继承的目的:实现设计与代码的重用;
② 派生的目的:当新的问题出现,原有程序无法解决(或不能完全解决时),需要对原有程序进行改造。
4.
多继承:一个派生类,可以同时有多个基类;
单继承:一个派生类只有一个直接基类。
① 单继承时派生类的定义:(代码)
语法:
class 派生类名:继承方式 基类名
{
成员说明;
};
eg:
1 class Derived :public Base 2 { 3 public: 4 Derived(); 5 ~Derived(); 6 };
② 多继承时派生类的定义:(代码)
语法:
class 派生类名:继承方式1 基类名1,继承方式2 基类名2,...
{
成员说明;
};
注意:每一个“继承方式”,只用于限制对紧随其后之基类的继承。
eg:
1 class Derived :public Base1,private Base2 2 { 3 public: 4 Derived(); 5 ~Derived(); 6 };
5. 继承方式
① 继承方式关键字:
public(公有继承)、protected(保护继承)、private(私有继承);
② 继承方式规定了如何访问从基类继承的成员;
·基类公有成员=派生类公有成员,即派生类可以像访问自身的公有成员一样访问基类的公有成员;
·基类保护成员=派生类保护成员,即派生类可以像访问自己的保护成员一样访问基类的保护成员;
·基类私有成员:派生类的内部成员无法直接访问。派生类的使用者也无法通过派生类对象直接访问基类的私有成员。
总结:
派生类不能直接使用基类私有成员;
派生类可以直接使用基类公有/保护成员;
③ 如果不显式地给出继承方式关键字,系统的默认值就认为是私有继承(private);
6. 派生类成员是指除了从基类继承来的所有成员之外,新增加的数据和函数成员。
二、 派生类的生成过程
1. 步骤:吸收基类成员、改造基类成员、添加新的成员。
(1) 吸收基类成员:
① 默认情况下派生类包含了全部基类中除构造函数和析构函数之外的所有成员;
② C++11规定可以用using语句继承基类构造函数;
③ 在定义派生类之后自动完成。
(2) 改造基类成员:
① 包括两个方面:基类成员的访问控制问题、对基类数据或函数成员的覆盖和隐藏;
② 如果派生类声明了一个和某基类成员同名的新成员(如果是成员函数,则参数表也要相同,参数不同的情况属于重载),派生的新成员就隐藏了外层同名成员。
这时在派生类中或者通过派生类的对象,直接使用成员名就只能访问到派生类中声明的同名成员,叫做同名隐藏。
(3) 添加新的成员:
① 需要在派生类中加入新的构造和析构函数。
三、 3种继承方式
·包括:public(公有继承)、protected(保护继承)、private(私有继承);
·不同继承方式的影响主要体现在:
① 派生类成员对基类成员的访问权限;
② 通过派生类对象对基类成员的访问权限。
1. 公有继承(最宽泛、最常用的一种继承)
· 基类的public和protected成员:访问属性在派生类中保持不变;
· 基类的private成员:不可直接访问。
▲访问权限:
· 派生类中的成员函数:可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员;
· 通过派生类的对象:只能访问派生类的public成员(包括继承的public成员)。
举例说明(代码如下):
1 #include <iostream> 2 using namespace std; 3 4 class Base 5 { 6 public: 7 Base(int nId) { mId = nId; } 8 int Id() { mId++; cout << mId << endl; return mId; } 9 protected: 10 int Num() { cout << 0 << endl; return 0; } 11 private: 12 int mId; 13 }; 14 15 class Child : public Base 16 { 17 public: 18 Child() : Base(7) { ; } 19 int newId() { return Id(); } //新增成员可以访问公有成员 20 int newNum() { return Num(); } //新增成员可以访问保护成员 21 //无法访问基类的私有成员 22 protected: 23 int y; 24 private: 25 int x; 26 }; 27 28 int main() 29 { 30 Child child; 31 child.Id(); //派生类的对象可以访问派生类继承下来的公有成员 32 //child.GetNum(); //无法访问继承下来的保护成员Num() 33 child.newId(); 34 child.newNum(); //派生类对象可以访问派生类的公有成员 35 //child.x; 36 //child.y; //无法访问派生类的保护成员y和私有成员x 37 return 0; 38 }
2. 私有继承(最严格的一种继承;很少使用)
· 基类的public和protected成员:都以private身份出现在派生类中;
· 基类的private成员:不可直接访问。
▲访问权限:
· 派生类中的成员函数:可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员;
· 通过派生类的对象:不能直接访问从基类继承的任何成员。
举例说明(代码如下):
1 class Child : private Base 2 { 3 public: 4 Child() : Base(7) { ; } 5 int newId() { return Id(); } //可以访问基类的公有成员和保护成员 6 int newNum() { return Num(); } 7 protected: 8 int y; 9 private: 10 int x; 11 }; 12 13 int main() 14 { 15 Child child; 16 //child.Id();//派生类对象访问不了继承的公有成员,因为此时私有继承时newId()已经为private类型 17 //child.Num(); //派生类对象访问不了继承的保护成员,而且此时私有继承时newNum()已经为private类型 18 child.newId(); 19 child.newNum(); 20 return 0; 21 }
3. 保护继承(介于公有和私有之间)
· 基类的public和protected成员:都以protected身份出现在派生类中;
· 基类的private成员:不可直接访问。
▲访问权限:
· 派生类中的成员函数:可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员;
· 通过派生类的对象:不能直接访问从基类继承的任何成员。
举例说明(代码如下):
1 class Child : protected Base 2 { 3 public: 4 Child() : Base(7) { ; } 5 int newId() { return Id(); } //可以访问基类的公有成员和保护成员 6 int newNum() { return Num(); } 7 protected: 8 int y; 9 private: 10 int x; 11 }; 12 13 int main() 14 { 15 Child child; 16 //child.Id();//派生类对象访问不了继承的公有成员,因为此时保护继承时Id()已经为protected类型 17 //child.Num(); //这个也访问不了 18 child.newId(); 19 child.newNum(); 20 return 0; 21 }
注:protected成员的特点与作用
① 对建立其所在类对象的模块来说,它与private成员的性质相同。绝不可能被其他外部使用者(比如程序中的普通函数、与其类平行的其他类)等访问。
② 对于其派生类来说,它与public成员的性质相同。
③ 既实现了数据隐藏,又方便继承,实现代码重用。
举例说明(代码如下):
1 class A { 2 protected: 3 int x; 4 }; 5 class B :public A { //公有派生 6 public: 7 void function(); 8 }; 9 void B::function() { 10 x = 5; 11 }
注:如果B是A的派生类,B的成员函数只能通过B的对象访问A中定义的protected成员,而不能通过A的对象访问A的protected成员。
★总结:
不管是哪种继承方式,派生类中新增成员可以访问基类的公有成员和保护成员,无法访问私有成员。而继承方式影响的是派生类继承成员访问属性,而使用友元(friend)可以访问保护成员和私有成员。