C++初学者指南 第十篇(3)
来源:互联网 发布:手机淘宝和天猫哪个好 编辑:程序博客网 时间:2024/05/16 01:14
必备技能10.3:使用保护的成员
正如我们所讨论的那样,基类的私有成员在派生类中是不能被访问的。这样一来,如果派生类想要访问基类的成员,似乎只能把这些成员在基类中声明为公有的了。但是,这样以来,程序中的其它代码也是可以访问这些公有成员的,这不是我们想要的。幸运的是,C++允许我们创建保护的成员,从而没有必要把派生类访问的成员在基类中声明为公有的。保护的成员在类的继承关系中是公有的,但是对于继承关系之外的代码来说又是私有的。
保护成员的创建是通过使用protected修饰符来完成的。当类的一个成员被声明为protected的时候,该成员就是私有的,只有一种情况例外。就是当该保护成员被继承的时候。此时,派生类是可以访问基类的保护成员的。因此,通过使用保护成员,我们就可以创建对于自身来说是私有的,但是派生类又可以访问的类的成员。protected修饰符也可以用于结构体。
下面的程序演示了保护成员:
//演示保护成员#include <iostream>using namespace std; class B{protected: int i,j;public: void set( int a, int b ) { i = a; j = b; } void show() { cout << i << " " << j << "\n"; }}; class D : public B{ int k;public: //D可以访问B类中的i和j。这是因为他们是保护的,而非私有的。 void setk() { k = i * j; } void showk() { cout << k << "\n"; } }; int main(){ D ob; ob.set(1,2); //访问基类的共有成员 ob.show();//访问基类的共有成员 ob.setk(); ob.showk();//访问派生类的公有成员 return 0;}
其中由于D公有地继承了B类,并且i和j在B类中被声明为保护成员,所以D的函数setk()就可以访问它们。如果i和j被声明为是private的,那么D就不能访问它们,程序也就不能成功编译了。
当派生类以公有的方式继承基类的时候,基类中的保护成员在派生类中也是保护成员。当基类被以私有的方式继承的时候,基类的保护成员在派生类中就变成了私有的成员了。
protected修饰符在声明类的时候可以出现在任何位置,但是通常它是被写在类的私有成员之后,而在共有成员之前。因此,最常用的完整的类的声明形式如下:
class 类名
{
private:
//私有成员,缺 省就是私有的。
protected:
//保护成员
public:
//共有成员
};
当然,其中的protected是一个可选项。
除了上面的类的保护成员外,关键字protected也可以用于基类被继承时候的访问限定符。当基类以保护的方式被继承的时候,其所有的公有和保护成员在派生类中都变成了保护成员。例如:
class D : protected B
{
///.....
};
那么,B中所有的非私有成员在D中都变成了保护的。
练习:
1. 当基类以private的方式被继承的时候,它的公有成员在派生类中都成了私有的成员。对吗?
2. 基类中的私有成员可否通过继承的方式在派生类中变成共有的?
3. 在继承关系中,使用哪个访问限定符可以使得基类的成员可以被访问,而不是私有的不能访问。
专家答疑
问:能对public,protected和private进行一个总结吗?
答:当类的成员被声明为共有的,它是可以被程序中任何的代码访问的。当类的成员被声明私有的,它只能被该类本身的成员访问。派生类不能访问基类中的私有成员。当一个成员被声明为保护的时候,它只能被自身类及其子类访问。所以,保护成员可以被继承但是在继承关系中则为私有的。
当基类以公有的方式被继承的时候,它的公有成员在派生类中依然是公有的,它的保护成员在派生类依然是保护的。当基类被以保护的方式继承的时候,它的公有和保护成员则在派生类中都变成了保护的。当基类被以私有的方式继承的时候,它的公有和保护成员在派生类中都是私有的。无论什么情况,基类中私有的成员都永远是该基类私有的。
构造函数与继承
在继承关系中,基类和派生类有可能都有自己的构造函数,这就存在一个很重要的问题:到底调用哪个构造函数来生成派生类的对象了,基类的构造函数,还是派生类的构造函数,或者两者都调用?这个问题的答案是这样的:基类的构造函数负责构建该对象的基类部分,派生类的构造函数负责构建该对象的派生类部分。这样做是合理的,这是因为基类是不能感知并访问派生类的成员的。因此它们各自部分的构造必须是分开的。前面的示例程序中采用了C++提供的缺省的构造函数,因此没有什么问题。但是,实际应用中大部分的类都会定义构造函数。这里我们就针对这种情况进行讨论。
当只有派生类中定义了构造函数的时候,处理起来很简单:直接生成派生类的对象。其中基类的部分自动调用缺省的构造函数。例如,下面是Triangle类的另外一个版本,这个版本中,我们为Triangle类定义了构造函数。同时,还把style成员声明为私有的,它在构造函数中被赋值。
// 为Triangle类定义构造函数 #include <iostream>#include <cstring>using namespace std; //二维对象类class TwoDShape{ double width; double height;public: void showDim() { cout << "Width and height are " << width << " and " << height << "\n"; } //访问函数 double getWidth() { return width; }; double getHeight() { return height; }; void setWidth(double w ) { width = w ; }; void setHeight(double h ) { height = h; };}; //Triangle类是从TwoDShape类中继承而来的class Triangle : public TwoDShape{ char style[20]; public: // 构造函数 Triangle( char *str, double w, double h) { //初始化TwoDShape的部分 setWidth(w); setHeight(h); //对Triangle类特有的部分进行初始化 strcpy(style,str); } double area() { return getWidth() * getHeight() / 2; } void showStyle() { cout << "Triangle is " << style << "\n"; }};
其中,Triangle类的构造函数对从TwoDShape类中继承来的以及自己增加的成员都进行了初始化。
当基类和派生类中都定义了构造函数的时候,情况就有点复杂,因为此时基类和派生类的构造函数都是要被执行的。
- C++初学者指南 第十篇(3)
- C++初学者指南 第十篇(1)
- C++初学者指南 第十篇(2)
- C++初学者指南 第十篇(4)
- C++初学者指南 第十篇(5)
- C++初学者指南 第十篇(6)
- C++初学者指南 第十篇(7)
- C++初学者指南 第十篇(8)
- C++初学者指南 第十篇(9)
- C++初学者指南 第十篇(10)
- C++初学者指南 第十篇(11)
- C++初学者指南 第十篇(12)
- C++初学者指南 第十一篇(3)
- C+++初学者指南+第六篇(5)
- C+++初学者指南+第六篇(6)
- C+++初学者指南+第六篇(7)
- C++:初学者的指南
- Objective-C 初学者指南
- UNICODE常用字符串函数。
- android输入子系统模型分析:
- OpenSSL: 椭圆曲线签名与校验 (ECDSA)
- shell批量修改文件名
- 保护器件应用
- C++初学者指南 第十篇(3)
- bash 字符串处理
- 进程和线程的区别
- 详解MeeGo Touch服务框架
- c# xml
- 把PD自动生成的ORACLE脚本去除双引号
- 打印Hello World,填空题
- 清单生成和编辑工具 (Mage.exe)
- 一个学习例子