三种继承
C++有下面三种形式的继承
(1) 公有继承(public)
公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的,不能被这个派生类的子类所访问。
(2)私有继承(private)
私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。
(3)保护继承(protected)
保护继承的特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。
private能够对外部和子类保密,即除了成员所在的类本身可以访问之外,别的都不能直接访问。protected能够对外部保密,但允许子类直接访问这些成员。public、private和protected对成员数据或成员函数的保护程度可以用下表来描述:
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
#include<iostream> #include<stdlib.h> using namespace std; class Base //父类 { private: int privateTemp; protected: int protectedTemp; public: int publicTemp; }; class publicClass : public Base //子类,继承自base,继承类型为公有继承 { private: int _d_pri; protected: int _d_pro; public: void funct() { int d; d = privateTemp; //error:基类中私有成员在派生类中是不可见的 d = protectedTemp; //ok: 基类的保护成员在派生类中为保护成员 d = publicTemp; //ok: 基类的公共成员在派生类中为公共成员 } int _d_pub; }; //总结:(1).public继承是一个接口继承,保持is - a原则,每个父类可用的成员对子类也可用, 因为每个子类对象也都是一个父类对象。 class privateClass :private Base //基类Base的派生类C(私有继承) { public: void funct() { int c; c = privateTemp; //error:基类中私有成员在派生类中是不可见的 c = protectedTemp; //ok:基类的保护成员在派生类中为私有成员 c = publicTemp; //ok:基类的公共成员在派生类中为私有成员 } }; class protectedClass :protected Base //基类Base的派生类E(保护继承) { public: void funct() { int e; e = privateTemp; //error:基类中私有成员在派生类中是不可见的 e = protectedTemp; //ok:基类的保护成员在派生类中为保护成员 e = publicTemp; //ok:基类的公共成员在派生类中为保护成员 } }; //总结: //(2).基类的private成员 在派生类中是不能被访问的, 如果基类成员 不想在类外直接被访问, 但需要 在派生类中能访问, 就定义为protected。 可以看出保护成员限定符是因继承才出现的。 //(3). protected / private继承是一个实现继承, 基类的部分成员 并非完全成为子类接口 的一部分, 是 has - a 的关系原则, 所以非特殊情况下不会使用这两种继承关系, 在绝大多数的场景下使用的 都是公有继承。 私有继承以为这is - implemented - in - terms - of(是根据……实现的) 。 通常比组合(composition) 更低级, 但当一个派生类需要访问 基类保护成员 或需要重定义基类的虚函数时它就是合理的。 int main() { int a; publicClass d; a = d.privateTemp; //error:公有继承基类中私有成员在派生类中是不可见的,对对象不可见 a = d.protectedTemp; //error:公有继承基类的保护成员在派生类中为保护成员,对对象不可见 a = d.publicTemp; //ok:公有继承基类的公共成员在派生类中为公共成员,对对象可见 privateClass c; a = c.privateTemp; //error:私有继承基类中私有成员在派生类中是不可见的, 对对象不可见 a = c.protectedTemp; //error:私有继承基类的保护成员在派生类中为私有成员,对对象不可见 a = c.publicTemp; //error:私有继承基类的公共成员在派生类中为私有成员,对对象不可见 protectedClass e; a = e.privateTemp; //error:保护继承基类中私有成员在派生类中是不可见的, 对对象不可见 a = e.protectedTemp; //error:保护继承基类的保护成员在派生类中为保护成员,对对象不可见 a = e.publicTemp; //error:保护继承基类的公共成员在派生类中为保护成员,对对象不可见 system("pause"); return 0; } |
编译器具体效果
总结
(1)public继承是一个接口继承,保持is - a原则,每个父类可用的成员对子类也可用, 因为每个子类对象也都是一个父类对象。
(2)基类的private成员 在派生类中是不能被访问的, 如果基类成员 不想在类外直接被访问, 但需要 在派生类中能访问, 就定义为protected。 可以看出保护成员限定符是因继承才出现的。
(3) protected / private继承是一个实现继承, 基类的部分成员 并非完全成为子类接口 的一部分, 是 has - a 的关系原则, 所以非特殊情况下不会使用这两种继承关系, 在绝大多数的场景下使用的 都是公有继承。 私有继承以为这is - implemented - in - terms - of(是根据……实现的) 。 通常比组合(composition) 更低级, 但当一个派生类需要访问 基类保护成员 或需要重定义基类的虚函数时它就是合理的。
如果想要用基类的私有成员初始化怎么办?解决方法如下。
如何调用基类私有成员
首先声明一点:类的构造函数和析构函数不能被继承。
所以要用到基类的私有成员初始化必须在派生类中定义一个构造函数并显式调用基类的构造函数。
加一个冒号(:),然后加上父类的带参数的构造函数。这样,在子类的构造函数被调用时,系统就会去调用父类的带参数的构造函数去构造对象。应该这样调用(Square继承自Rectangle)
1 |
Square(string n, double x):Rectangle(n, x, x){} |
具体实例代码
题目:编程计算图形的面积。程序可计算圆形、长方形、正方形的面积,运行时先提示用户选择图形的类型,然后,对圆形要求用户输入半径值,对长方形要求用户输入长和宽的值,对正方形要求用户输入边长的值,计算出面积的值后将其显示出来。
长方形类设计:
私有变量为:名称、宽度、长度、面积。
成员函数包括:构造函数、信息显示函数、求面积函数。
正方形类设计:
正方形类公有继承自长方形类:当类的继承方式为公有继承时,基类的公有成员和保护成员的访问属性在派生类中不变,而基类的私有成员不可直接访问。
正方形类显式调用长方形类的构造函数如下:
私有变量为:名称、边长、面积。
成员函数包括:构造函数、信息显示函数、求面积函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
#include<iostream> #include<string> #include<stdlib.h> #define pi 3.1415927 using namespace std; class Rectangle{ private: string name; double width; double height; double area; public: Rectangle(string x, double w, double h) :name(x), width(w), height(h){} void showInfo(); double getArea(){ return width*height; } }; void Rectangle::showInfo(){ if (width == height){ cout << "正方形: 边长为:" << width << endl; } else{ cout << "长方形: 长为:" << width << " 宽为:" << height << endl; } cout << "面积为:" << getArea() << endl; } class Square :public Rectangle{ private: string name; double width; double area; public: Square(string n, double x) :Rectangle(n, x, x){} }; class Circle{ private: string name; double radius; public: Circle(string x, double r) :name(x), radius(r){} double getArea(){ return pi*radius*radius; } void showInfo(){ cout << "圆:半径为:" << radius << endl << "面积为:" << getArea() << endl; } }; int main() { cout << "--------------------------" << endl; int choice; cout << "选择序号建立图形\n1:长方形 2:正方形 3:圆\n"; cin >> choice; while (1){ if (choice == 1){ cout << "输入长和宽:"; int width, height; cin >> width >> height; Rectangle a("Rectangle", height, width); a.showInfo(); } else if (choice == 2){ cout << "输入边长:"; int width2; cin >> width2; Square b("Square", width2); b.showInfo(); } else{ cout << "输入半径:"; int radius; cin >> radius; Circle c("Circle", radius); c.showInfo(); } system("pause"); system("cls"); cout << "选择序号建立图形\n1:长方形 2:正方形 3:圆\n"; cin >> choice; } } |
网站所有原创代码采用Apache 2.0授权
网站文章采用知识共享许可协议BY-NC-SA4.0授权