c++代码重用—私有继承(学习笔记)

继承的准则

  • 派生类不继承基类的接口 >因为基类的公有方法成为派生类的私有方法
  • 派生类会继承实现

student类示例

1.私有继承的声明

1 class student:private std::string,private std::valarray < double >
2 {  
3     public:
4     ....
5 };

需要注意的问题:

  1. private是默认值,如果这里省略,也会导致私有继承
  2. 使用多个基类的继承也被称为multiple inheritance在下一节中了解
  3. 最重要的一点:student这个新的类不需要私有数据,私有继承为他提供了两个无名称的子对象成员

 


2.初始化基类组件

因为,私有继承为派生类提供了两个无名称的子对象成员,那么,我们也就不能再像之前那样,使用对象名去初始化,这也是这两个student类的第二个区别:

  • 使用类名,而不是对象名
    1 student(const char* str,const double* pD, int n)
    2     :std::string(str),ArrayDb(pd,n){}

    说明:
    typedef std::valarray< double > ArrayDb

    • ArrayDb是std::valarrayDb的别名

    头文件如下所示

 1 #ifndef STUDENT_H_
 2 #define STUDENT_H_
 3 
 4 #include
 5 #include
 6 #include
 7 
 8 class student:private std::string,private std::valarray
 9 {
10 private:
11     typedef std::valarray ArrayDb;
12     std::ostream & arr_out(std::ostream& os)const;
13 public:
14     student():std::string("Null Student"),ArrayDb(){}
15     explicit student(const std::string& s)
16         :std::string(s),ArrayDb(){}
17     explicit student(int n):std::string("Nully"),ArrayDb(n){}
18     student(const std::string& s,int n)
19         :std::string(s),ArrayDb(n){}
20     student(const std::string & s,ArrayDb & a)
21         :std::string(s),ArrayDb(a){}
22     student(const char* str,const double* pd,int n)
23         :std::string(str),ArrayDb(pd,n){}
24     ~student(){}
25     double average() const;
26     double & operator[](int i);
27     double operator[](int i)const;
28     const std::string & Name() const;
29     //friends
30     friend std::istream & operator>>(std::istream & is,
31                               student & stu);
32     friend std::istream & getline(std::istream & is,
33                               student & stu);
34     friend std::ostream & operator<<(std::ostream & os,
35                              const student & stu);
36 };
37 #endif

程序说明:

1 student(const std::string & s,ArrayDb & a)
2         :std::string(s),ArrayDb(a){}

在valarray概念的时候说过,valarray对象有很多的构造函数,其中有一种如下:

1 valarray< double >v4(gpa,4);
  • 声明一个四个元素的数组,并用gap(也是valarray的一个对象)的前4个元素去初始化。

3.访问基类的方法

在我们使用私有继承的时候,如何使用基类的方法呢?

记住:只能在派生类的方法中去使用基类的方法,同时,使用类名和作用域解析运算符来调用基类方法

我们看两段代码的比较:
(1)包含

 1 double student::average()const
 2 {
 3     if(scores.size()>0)
 4     {
 5         return scores.sum()/scores.size();
 6     }
 7     else
 8     {
 9         return 0;
10     }
11 }

(2)私有继承

 1 double student::average()const
 2 {
 3     if(ArrayDb::size()>0)
 4     {
 5         return ArrayDb::sum()/ArrayDb::size();
 6     }
 7     else
 8     {
 9         return 0;
10     }
11 }
  • 只能在派生类的方法中去使用基类的方法,同时,使用类名和作用域解析运算符来调用基类方法

4.访问基类对象

先回顾一段代码片段

1 const string & student::Name()const
2 {
3     return name;
4 }

这是包含版本中用来返回数据成员的名字的,该数据成员是string对象,
名称设为name,但是我们知道,在私有继承中,提供的是两个无名称的子对象成员, 
那么该怎么访问基类的对象呢?

    • 强制类型转换 具体代码片段如下:
      1 const string & student::Name()const
      2 {
      3 return (const string &)*this
      4 }

      说明:

      • 很明显,student是从string派生而来,因此,我们可以使用强制类型转换,
        将student对象转换为string对象,转换结果:继承而来的string对象

      • this指针指向调用该方法的对象,那么*this也就是该对象的本身,在这段代码中指的就是student,

      • 为了避免构造函数创建新的对象,可以使用强制类型转换来创建一个引用,并返回返回引用,该引用指向调用该方法的student对象中的继承而来的string对象。


      5.访问基类的友元函数

      如果还去使用类名和作用域解析运算符来调用友元函数,显然就不太合适了,因为,从概念上来说,友元函数并不属于成员函数。

      • 解决办法:将派生类的引用显示的转换为基类的引用,从而调用友元函数。

      代码片段如下:

      1 ostream & operator<<(std::ostream & os,const student & stu)
      2 {
      3     os<< "scores for "<< (const string &)stu<< ":\n";
      4     return os;
      5 }

      记住一点:stu之所以不会自动转换为string的引用,根本原因:未经过显示转换的派生类的引用或指针,是不能赋值给基类的引用或指针。(什么意思啊?)

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。