C++has-a关系

一、包含关系
简单地说就是“对象中的对象”,一个类中包含是一个类成员。

class Student
{
    private:
        string name;   //一个string类对象
        valarray<double> scores;   //一个valarray<double>类对象
        ...
};

在包含关系中通过对象名来调用被包含类对象的公有方法。例如上面:
name.size();
score.sum();

注意:接口和实现
使用公有继承,类可以继承接口,可能还有实现(基类的纯虚函数提供接口但不提供实现)。获得接口是is-a关系。但使用组合,类可以获得实现,但不能获得接口。不继承接口是has-a的组成部分。

1)初始化被包含的对象
对于继承的对象,构造函数在成员初始化列表中调用特定的基类构造函数。对于成员对象,构造函数使用成员名。因此在包含关系中,例如:
student(constr char str, const double * pd, int n)
: name(str), scores(pd, n) {}
该构造函数初始化的是成员对象,而不是继承的对象。
2)使用被包含对象的接口
被包含对象的借口不是公有的,但可以在类方法中使用它。

二、私有继承
C++还有一种实现has-a关系的方法——私有继承。
使用私有继承,基类的共有成员和私有成员都将成为派生类的私有成员,意味着基类方法不会成为派生类对象公有接口的一部分,但仍可在派生类成员函数中会用。
包含和私有继承区别之一是包含为类提供两个被显式命名的对象成员,但私有继承提供了两个无名称的子类对象。在私有继承中使用类名和作用域解析符来调用基类的方法。
string::size();
valarry::sum();

1)初始化基类组件
因为私有继承是继承所以在构造函数中应使用类名来表示构造函数,例如:
student(constr char str, const double * pd, int n)
: string(str), ArrayDb(pd, n) {}
上面ArrayDb是valarray的别名。
2)访问基类方法
在私有继承中使用类名和作用域解析符来调用基类的方法。
string::size();
valarry::sum();
3)访问基类对象
使用强制类想转换将派生类对象转化为基类对象,结果为继承来的基类对象。
const string & Student::Name() const
{
return (const string &) *this;
}
4)访问基类的友元函数
用类名显式的限定函数名不适用于友元函数,因为友元函数不属于类。但可以使用显式的转化为基类来调用正确的函数。

三、使用包含和使用私有继承的选择
在选择上,包含是首选。因为首先,易于理解,使用私有继承是关系抽象。其次继承会引起许多问题,特别是在从多个基类继承时,二义性等等问题。另外,包含可以包含多个相同子类的对象,如包含3个string类对象。
然而,越难理解就说明继承包含的特性越多。当基类含有保护成员时,这样在派生类可用,但在继承类外不可用。另外,派生类可以重新定义虚函数,但包含不可以。

四、附加:保护继承
使用保护继承时,基类的公有成员都将成为派生类的保护成员。积累的接口在派生类中可用,继承层次结构外是不可用的。
但是当刚从派生类再派生一个类时,私有继承第三代类不可使用积累的接口,这是因为基类的共有方法在私有继承中变成了私有成员;使用保护继承时,基类的公有成员在第二代中变成受保护的,因此在第三代中可使用。
使用using重定义访问权限:让基类的方法在派生类外可用。
class Student : private string, private valarray
{

public:
using valarray::min;
using valarray::max;

};
使用以上声明使得Student像使用自己公有方法一样使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值