C++ | 代码重用 | 私有继承

私有继承是C++中实现has-a关系的另一种途径。使用私有继承,基类的公有成员和保护成员都将称为派生类的私有成员。换言之,基类方法不会成为派生对象公有接口的一部分,只可以在派生类的成员函数中使用。

  • 公有继承:基类公有方法将成为派生类的公有方法;派生类继承基类的接口,是is-a关系。
  • 私有继承:基类公有方法将成为派生类的私有方法;派生类不继承寄了的接口,是has-a关系。

私有继承提供的特性与包含相同;获得实现,但不获得接口。

class Student : private std::string, private std::valarray<double> {
 public:
    ...// func body
}

1  初始化基类组件

项目包含私有继承
成员对象提供了被显示命名的对象成员提供了无名称的子对象成员
成员列表初始化使用name(str)使用std::string(str)
实现关系has-ahas-a
//use object names for containment
class Student {
 private:
    typedef std::valarray<double> ArrayDb;
    std::string name;
    ArrayDb score;
};
Student(const char* str, const double* pd, int n) 
    : name(str), score(pd, n) {}

//use class name for inheritance
class Student : private std::string, private std::valarray<double> {
 public:
    ...// func body
}
Student(const char* str, const double* pd, int n) 
    : std::string(str), ArrayDb(pd, n) {}

代码中第二种方法,class Student继承了类std::string和std::valarray<double>,所以string和valarray是Student类的基类。

2 访问基类的方法

私有继承只能在派生类的方法中使用基类的方法。

包含使用对象来调用方法:

double Student::Average() const {
    if (score.size() > 0)
        return score.sum() / score.size();
    else
        return 0;
}

私有继承使用类名和作用域解析运算符来调用基类的方法:

double Student::Average() const {
    if (ArrayDb::size() > 0)
        return ArrayDb::sum() / ArrayDb::size();
    else
        return 0;
}

通过上面两个例子可以看到:

  • 使用包含时将使用对象名来调用方法;
  • 使用私有继承时将使用类名和作用域解析运算符来调用方法。

3 访问基类对象本身

通过使用作用域解析运算符可以访问基类的方法,那么若要访问基类本身该怎么办?

可以通过强制类型转换实现访问基类本身。

指针 this 指向用来调用方法的对象,*this 为用来调用方法的对象。

const string &Student::Name() const {
    return (const string &) *this;  //将对象强制转换为基类string
}

4 访问基类友元函数

首先,友元函数不是不属于类,所以通过使用类名显示地限定函数名不适合调用友元函数。可以通过显示地转换为基类来调用正确的函数(如下)。

friend std::ostream &operator<<(ostream &os, const Student &stu);
ostream &operator<<(ostream &os, const Student &stu) {
    //显示转换为基类进行调用
    os << "Scores for " << (const string &) stu << ":\n;
    ...
}

在私有继承中,未进行显示类型转换的派生类引用或指针,无法赋值给基类的引用或指针。

5 包含和私有继承的选择

虽然两种方式都可以使用,都建立has-a关系,且可以完成同样的工作。但大多数C++程序员倾向于使用包含。

包含

  • 包含简单,类声明中包含表示被包含类的显示命名对象,可以通过名称引用对象。包
  • 含能够包括多个同类的子对象(例如可以声明3个独立的string)。
  • 对于保护成员不能访问。
  • 无法重新定义虚函数。

私有继承

  • 继承使得关系更加抽象,同时当从多个基类继承时可能会引发一系列问题,需要特殊处理。
  • 继承只能使用一个这样的对象。
  • 继承具有更多的特性,当含有保护成员时,派生类可以使用。
  • 可以重新定义虚函数。

通常,应使用包含来建立has-a关系;如果新类需要访问原有类的保护成员,或需要重新定义虚函数,应使用私有继承。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值