c++代码重用—私有继承(学习笔记)
继承的准则
- 派生类不继承基类的接口 >因为基类的公有方法成为派生类的私有方法
- 派生类会继承实现
student类示例
1.私有继承的声明
1 class student:private std::string,private std::valarray < double > 2 { 3 public: 4 .... 5 };
需要注意的问题:
- private是默认值,如果这里省略,也会导致私有继承
- 使用多个基类的继承也被称为multiple inheritance在下一节中了解
- 最重要的一点: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的引用,根本原因:未经过显示转换的派生类的引用或指针,是不能赋值给基类的引用或指针。(什么意思啊?)
-
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。