星球狂想战队|一起来学C++:C++中的代码重用( 七 )


5.使用修改后的Student类接下来也需要测试这个新类 。 注意到两个版本的Student类的公有接口完全相同 , 因此可以使用同一个程序测试它们 。 唯一不同的是 , 应包含studenti.h而不是studentc.h , 应使用studenti.cpp而不是studentc.cpp来链接程序 。 程序清单14.6列出列该程序 , 请将其与studenti.cpp一起编译 。
程序清单14.6use_stui.cpp
//use_stui.cpp--usingaclasswithprivateinheritance//compilewithstudenti.cpp#include#include"studenti.h"usingstd::cin;usingstd::cout;usingstd::endl;voidset(Student&sa,intn);constintpupils=3;constintquizzes=5;intmain(){Studentada[pupils]={Student(quizzes),Student(quizzes),Student(quizzes)};inti;for(i=0;i<pupils;i++)set(ada[i],quizzes);cout<<"nStudentList:n";for(i=0;i<pupils;++i)cout<<ada[i].Name()<<endl;cout<<"nResults:";for(i=0;i<pupils;i++){cout<<endl<<ada[i];cout<<"average:"<<ada[i].Average()<<endl;}cout<<"Done.n";return0;}voidset(Student&sa,intn){cout<<"Pleaseenterthestudent'sname:";getline(cin,sa);cout<<"Pleaseenter"<<n<<"quizscores:n";for(inti=0;i<n;i++)cin>>sa[i];while(cin.get()!='n')continue;}下面是该程序的运行情况:
Pleaseenterthestudent'sname:GilBaytsPleaseenter5quizscores:9294969395Pleaseenterthestudent'sname:PatRoonePleaseenter5quizscores:8389727895Pleaseenterthestudent'sname:FleurO’DayPleaseenter5quizscores:9289967464StudentList:GilBaytsPatRooneFleurO'DayResults:ScoresforGilBayts:9294969395average:94ScoresforPatRoone:8389727895average:83.4ScoresforFleurO'Day:9289967464average:83Done.输入与前一个测试程序相同 , 输出也相同 。
14.2.2使用包含还是私有继承由于既可以使用包含 , 也可以使用私有继承来建立has-a关系 , 那么应使用种方式呢?大多数C++程序员倾向于使用包含 。 首先 , 它易于理解 。 类声明中包含表示被包含类的显式命名对象 , 代码可以通过名称引用这些对象 , 而使用继承将使关系更抽象 。 其次 , 继承会引起很多问题 , 尤其从多个基类继承时 , 可能必须处理很多问题 , 如包含同名方法的独立的基类或共享祖先的独立基类 。 总之 , 使用包含不太可能遇到这样的麻烦 。 另外 , 包含能够包括多个同类的子对象 。 如果某个类需要3个string对象 , 可以使用包含声明3个独立的string成员 。 而继承则只能使用一个这样的对象(当对象都没有名称时 , 将难以区分) 。
然而 , 私有继承所提供的特性确实比包含多 。 例如 , 假设类包含保护成员(可以是数据成员 , 也可以是成员函数) , 则这样的成员在派生类中是可用的 , 但在继承层次结构外是不可用的 。 如果使用组合将这样的类包含在另一个类中 , 则后者将不是派生类 , 而是位于继承层次结构之外 , 因此不能访问保护成员 。 但通过继承得到的将是派生类 , 因此它能够访问保护成员 。
另一种需要使用私有继承的情况是需要重新定义虚函数 。 派生类可以重新定义虚函数 , 但包含类不能 。 使用私有继承 , 重新定义的函数将只能在类中使用 , 而不是公有的 。
提示:
通常 , 应使用包含来建立has-a关系;如果新类需要访问原有类的保护成员 , 或需要重新定义虚函数 , 则应使用私有继承 。
14.2.3保护继承保护继承是私有继承的变体 。 保护继承在列出基类时使用关键字protected:
classStudent:protectedstd::string,protectedstd::valarray{...};使用保护继承时 , 基类的公有成员和保护成员都将成为派生类的保护成员 。 和私有继承一样 , 基类的接口在派生类中也是可用的 , 但在继承层次结构之外是不可用的 。 当从派生类派生出另一个类时 , 私有继承和保护继承之间的主要区别便呈现出来了 。 使用私有继承时 , 第三代类将不能使用基类的接口 , 这是因为基类的公有方法在派生类中将变成私有方法;使用保护继承时 , 基类的公有方法在第二代中将变成受保护的 , 因此第三代派生类可以使用它们 。