要点:
继承与派生的概念派生类的构造函数和析构函数的执行顺序与规则多继承的声明与实现基类成员访问原则赋值兼容性虚基类的概念继承是面向对象程序设计中重要的特性。继承主要是指在已有类的基础上创建新类的过程,这个新类就是派生类。派生类自动包含了基类的成员,包括所有的数据和操作,而且还可以增加自身新的成员。 一个派生类从两个或多个基类派生则称为多继承,这个我们后面会说到 继承机制除了支持软件复用外,还具备以下3个作用: (1)对事物进行分类可以把基类看成子类共性的抽象,换一个角度,即基类表达了该种类型的一般概念,而子类则表达了一个特殊概念。 (2)支持软件的增量开发。软件开发通常不是一次性完成的,往往是一个逐步升级、细化、改进的过程,派生类和基类的关系恰好能体现了这种改进和被改进的关系。 (3)对概念进行组合前面内容提过可以为类定义对象成员,这就是一种组合关系,而继承机制中,基类称为派生类的一部分,其实也就是一种组合的概念,尤其在多继承关系上,多个基类共同构成同一派生类。 派生类的声明
class 派生类名:继承方式 基类名 { 派生类成员声命 };继承方式,也称访问控制方式,用来限定紧随其后的基类,包括三种方式:public、private、protected,如果没有显式的使用这三个关键字之一进行声明,则系统默认为私有继承。类的继承方式指定了派生类成员函数以及类的对象对于从基类继承来的成员的访问权限,或者说决定了是基类成员在派生类中访问控制方式的变化。需要注意的是,基类的构造函数和析构函数不能被派生类继承,派生类若需要初始化基类的数据成员必须在构造函数中初始化。 这是基类
#include<iostream> #include<cmath> using namespace std; class Student { private: int number; string name; public: Student() { number = 0; name = ""; } void SetValue(int n,string s1) { number = n; name = s1; } void Print() { cout << "Number:" << number << endl; cout << "Name:" << name << endl; } };这是派生类
class Undergraduate :public Student { private: int age; int grade; public: Undergraduate() { age = 1; grade = 1; } Undergraduate(int n,string s1,int a,int g) { SetValue(n, s1); age = a; grade = g; } void PrintExtra() { cout << "Age:" << age << endl; cout << "Grade:" << grade << endl; } };由上述介绍我们可以知道派生类有三种继承方式,分别为public、private、protected。那么它们三者的区别是什么呢? 首先,我们先定义一个基类
class Base { private: int a; //基类私有成员a void Fun1() //基类私有成员函数Fun1 { cout << a << endl; } protected: int b; //基类受保护成员b void Fun2() //基类受保护成员函数Fun2 { cout << b << endl; } public: int c; //基类公有成员c void Fun3() //基类共有成元函数Fun3 { cout << c << endl; } void SetA(int i) //公有成员函数,可以修改私有成员a的值 { a = i; } int GetA() //公有成员函数,返回私有成员a的值 { return a; } Base(int i, int j, int k) //基类的构造函数 { a = i; b = j; c = k; } };(1)public继承时,基类成员的访问控制权限除私有成员外,在派生类中保持不变。 派生类的成员函数可以直接访问基类中的public、protected成员,以及本类所有权限的成员,基类的private私有成员虽然已经继承到派生类里,但是却无法实现直接访问,可以通过基类的public、protected 成员函数访问。 在类的作用域外的派生类对象只能访问基类的public成员和本类的public成员。
class Sub :public Base { private: int d; public: Sub(int i, int j, int k, int m) :Base(i, j, k) { d = m; } void Test() { cout << a << endl; //错误,无法访问基类的私有成员 cout << b << endl; //正确,可以访问基类的保护成员 cout << c << endl; //正确,可以访问基类的公有成员 Fun1(); //错误,无法访问基类的私有函数 Fun2(); //正确,可以访问基类的保护函数 Fun3(); //正确,可以访问基类的公有函数 SetA(10); //正确,可以间接访问基类的私有成员 cout << d << endl; //正确,可以访问派生类类的私有成员 } }; int main() { Base b1(5, 6, 7); //定义基类对象b1 cout << b1.a; //错误,无法访问对象的私有成员 cout << b1.b; //错误,无法访问对象的保护成员 cout << b1.c << endl; //正确,可以访问基类的公有成员c cout << b1.GetA() << endl; //正确间接访问对象的私有成员a Sub s1(11, 15, 19, 22); //定义派生类对象s1 s1.Test(); //正确,可以访问对象的公有成员 s1.c = 200; //正确,可以访问对象的公有成员 s1.Fun3(); //正确,可以访问对象的公有成员 return 0; }(2)protected继承时,基类成员对象的public访问权限在派生类中变为protected 派生类的成员函数可以直接访问基类中的public、protected成员,以及本类所有权限的成员,不能访问的是基类的private成员可以通过public、protected成元函数访问。 在作用域之外的派生类对象不能访问基类的所有权限的成员,但可以访问本类的public成员
class Sub :protected Base { private: int d; public: Sub(int i, int j, int k, int m) :Base(i, j, k) { d = m; } void Test() { cout << a << endl; //错误,无法访问基类的私有成员 cout << b << endl; //正确,可以访问基类的保护成员 cout << c << endl; //正确,可以访问基类的公有成员 Fun1(); //错误,无法访问基类的私有函数 Fun2(); //正确,可以访问基类的保护函数 Fun3(); //正确,可以访问基类的公有函数 SetA(10); //正确,可以间接访问基类的私有成员 cout << d << endl; //正确,可以访问派生类类的私有成员 } }; int main() { Base b1(5, 6, 7); //定义基类对象b1 cout << b1.a; //错误,无法访问对象的私有成员 cout << b1.b; //错误,无法访问对象的保护成员 cout << b1.c << endl; //正确,可以访问基类的共有成员c cout << b1.GetA() << endl; //正确间接访问对象的私有成员a Sub s1(11, 15, 19, 22); //定义派生类对象s1 s1.Test(); //正确,可以访问对象的公有成员 s1.c = 200; //错误,无法访问对象的公有成员 s1.Fun3(); //错误,无法访问对象的公有成员 return 0; }(3)private继承时,基类成员的public和protected访问权限在派生类中变为private。 派生类的成员函数可以直接访问基类中的public、protected成员,以及本类所有权限的成员,不能访问的是基类的private成员,但可以通过public、protected成员函数访问。
class Sub :private Base { private: int d; public: Sub(int i, int j, int k, int m) :Base(i, j, k) { d = m; } void Test() { cout << a << endl; //错误,无法访问基类的私有成员 cout << b << endl; //正确,可以访问基类的保护成员 cout << c << endl; //正确,可以访问基类的公有成员 Fun1(); //错误,无法访问基类的私有函数 Fun2(); //正确,可以访问基类的保护函数 Fun3(); //正确,可以访问基类的公有函数 SetA(10); //正确,可以间接访问基类的私有成员 cout << d << endl; //正确,可以访问派生类类的私有成员 } }; class Subsub :public Sub { public: void Test1() { cout << c << endl; //错误,无法访问基类公有成员 } }; int main() { Base b1(5, 6, 7); //定义基类对象b1 cout << b1.a; //错误,无法访问对象的私有成员 cout << b1.b; //错误,无法访问对象的保护成员 cout << b1.c << endl; //正确,可以访问基类的共有成员c cout << b1.GetA() << endl; //正确间接访问对象的私有成员a Sub s1(11, 15, 19, 22); //定义派生类对象s1 s1.Test(); //正确,可以访问对象的公有成员 s1.c = 200; //错误,可以访问对象的公有成员 s1.Fun3(); //错误,可以访问对象的公有成员 return 0; }总结: (1)基类的private成员在基类中任何方式都不能直接访问,只能通过基类的成员函数。 (2)在private、protected继承方式下,基类成员的权限都发生较大的变化,只有在特殊要求下才会使用,如希望在派生类的对象在类的作用域之外无法访问基类的public成员,就可以采用protected方式,在或者为了防止派生类还能被继续派生,就可以利用private方式把基类的访问权限都变为private,这样如果本派生类被非法取得并被继续派生,则原基类的成员在新派生类中就全部都无法访问了,这在一定程度上对原基类的使用许可起到了保护作用。 对于静态成员来说,静态成员函数与普通成员函数访问基类中的普通成员没有区别。
参考书籍:面向对象程序设计
