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


表14.1总结了公有、私有和保护继承 。 隐式向上转换(implicitupcasting)意味着无需进行显式类型转换 , 就可以将基类指针或引用指向派生类对象 。
表14.1各种继承方式
doubleStudent::sum()const//publicStudentmethod{returnstd::valarray::sum();//useprivately-inheritedmethod}这样Student对象便能够调用Student::sum() , 后者进而将valarray::sum()方法应用于被包含的valarray对象(如果ArrayDbtypedef在作用域中 , 也可以使用ArrayDb而不是std::valarray) 。
另一种方法是 , 将函数调用包装在另一个函数调用中 , 即使用一个using声明(就像名称空间那样)来指出派生类可以使用特定的基类成员 , 即使采用的是私有派生 。 例如 , 假设希望通过Student类能够使用valarray的方法min()和max() , 可以在studenti.h的公有部分加入如下using声明:
classStudent:privatestd::string,privatestd::valarray{...public:usingstd::valarray::min;usingstd::valarray::max;...};上述using声明使得valarray::min()和valarray::max()可用 , 就像它们是Student的公有方法一样:
cout<<"highscore:"<<ada[i].max()<<endl;注意 , using声明只使用成员名——没有圆括号、函数特征标和返回类型 。 例如 , 为使Student类可以使用valarray的operator方法 , 只需在Student类声明的公有部分包含下面的using声明:
usingstd::valarray::operator[];这将使两个版本(const和非const)都可用 。 这样 , 便可以删除Student::operator[]()的原型和定义 。 using声明只适用于继承 , 而不适用于包含 。
有一种老式方式可用于在私有派生类中重新声明基类方法 , 即将方法名放在派生类的公有部分 , 如下所示:
classStudent:privatestd::string,privatestd::valarray{public:std::valarray::operator[];//redeclareaspublic,justusename...};这看起来像不包含关键字using的using声明 。 这种方法已被摒弃 , 即将停止使用 。 因此 , 如果编译器支持using声明 , 应使用它来使派生类可以使用私有基类中的方法 。
14.3多重继承MI描述的是有多个直接基类的类 。 与单继承一样 , 公有MI表示的也是is-a关系 。 例如 , 可以从Waiter类和Singer类派生出SingingWaiter类:
classSingingWaiter:publicWaiter,publicSinger{...};请注意 , 必须使用关键字public来限定每一个基类 。 这是因为 , 除非特别指出 , 否则编译器将认为是私有派生:
classSingingWaiter:publicWaiter,Singer{...};//Singerisaprivatebase正如本章前面讨论的 , 私有MI和保护MI可以表示has-a关系 。 Student类的studenti.h实现就是一个这样的示例 。 下面将重点介绍公有MI 。
MI可能会给程序员带来很多新问题 。 其中两个主要的问题是:从两个不同的基类继承同名方法;从两个或更多相关基类那里继承同一个类的多个实例 。 为解决这些问题 , 需要使用一些新规则和不同的语法 。 因此 , 与使用单继承相比 , 使用MI更困难 , 也更容易出现问题 。 由于这个原因 , 很多C++用户强烈反对使用MI , 一些人甚至希望删除MI;而喜欢MI的人则认为 , 对一些特殊的工程来说 , MI很有用 , 甚至是必不可少的;也有一些人建议谨慎、适度地使用MI 。