在定义一个派生类时将基类的继承方式指定为public的,称为公用继承,用公用继承方式建立的派生类称为公用派生类(public derived class ),其基类称为公用基类(public base class )。
采用公用继承方式时,基类的公用成员和保护成员在派生类中仍然保持其公用成员和保护成员的属性,而基类的私有成员在派生类中并没有成为派生类的私有成员,它仍然是基类的私有成员,只有基类的成员函数可以引用它,而不能被派生类的成员函数引用,因此就成为派生类中的不可访问的成员。公用基类的成员在派生类中的访问属性见表11.1。
有人问,既然是公用继承,为什么不让访问基类的私有成员呢?要知道,这是C++中一个重要的软件工程观点。因为私有成员体现了数据的封装性,隐藏私有成员有利于测试、调试和修改系统。如果把基类所有成员的访问权限都原封不动地继承到派生类,使基类的私有成员在派生类中仍保持其私有性质,派生类成员能访问基类的私有成员,那么岂非基类和派生类没有界限了?这就破坏了基类的封装性。如果派生类再继续派生一个新的派生类,也能访问基类的私有成员,那么在这个基类的所有派生类的层次上都能访问基类的私有成员,这就完全丢弃了封装性带来的好处。保护私有成员是一条重要的原则。
[例11.1] 访问公有基类的成员。下面写出类的声明部分:
Class Student//声明基类 { public: //基类公用成员 void get_value( ) { cin>>num>>name>>sex; } void display( ) { cout<<" num: "<<num<<endl; cout<<" name: "<<name<<endl; cout<<" sex: "<<sex<<endl; } private: //基类私有成员 int num; string name; char sex; }; class Student1: public Student //以public方式声明派生类Student1 { public: void display_1( ) { cout<<" num: "<<num<<endl; //企图引用基类的私有成员,错误 cout<<" name: "<<name<<endl; //企图引用基类的私有成员,错误 cout<<" sex: "<<sex<<endl; //企图引用基类的私有成员,错误 cout<<" age: "<<age<<endl; //引用派生类的私有成员,正确 cout<<" address: "<<addr<<endl; } //引用派生类的私有成员,正确 private: int age; string addr; };
由于基类的私有成员对派生类来说是不可访问的,因此在派生类中的display_1函数中直接引用基类的私有数据成员num,name和sex是不允许的。只能通过基类的公用成员函数来引用基类的私有数据成员。可以将派生类Student1的声明改为
class Student1: public Student //以public方式声明派生类Student1 { public: void display_1( ) { cout<<" age: "<<age<<endl; //引用派生类的私有成员,正确 cout<<" address: "<<addr<<endl; //引用派生类的私有成员,正确 } private: int age;
string addr; };
然后在main函数中分别调用基类的display函数和派生类中的display_1函数,先后输出5个数据。
可以这样写main函数(假设对象stud中已有数据):
int main( ) { Student1 stud;//定义派生类Student1的对象stud stud.display( ); //调用基类的公用成员函数,输出基类中3个数据成员的值 stud.display_1(); //调用派生类公用成员函数,输出派生类中两个数据成员的值 return 0; }
请根据上面的分析,写出完整的程序,程序中应包括输入数据的函数。
实际上,程序还可以改进,在派生类的display_1函数中调用基类的display函数,在主函数中只要写一行:
stud.display_1();
即可输出5个数据。