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的引用,根本原因:未经过显示转换的派生类的引用或指针,是不能赋值给基类的引用或指针。(什么意思啊?)

时间: 2024-08-25 09:06:24

c++代码重用—私有继承(学习笔记)的相关文章

《C++ Primer Plus》14.2 私有继承 学习笔记

C++(除了成员变量之外)还有另一种实现has-a关系的途径——私有继承.使用私有继承,基类的公有成员和保护成员都将成为派生类的私有成员.(如果使用保护继承,基类的公有成员和保护成员都将称为派生类的保护成员.)这意味着基类方法将不会称为派生类对象共有接口的一部分,但可以在派生类的成员函数中使用它们.14.2.1 Student类示例(新版本)Student类应从两个类派生而来,因此声明将列出这两个类:class Student : private std::string, private std

c++代码重用—student(学习笔记)

第 14 章——C++中的代码重用 包含对象成员的类 14.1.1 valarray简介 头文件valarray支持的功能: 将数组中所用元素的值相加 找出最大最小值等操作 用valarray类声明一个对象 valarray < int > q_values; valarray < double > weights; 使用构造函数的代码片段 valarray< double > gpa[5] = {3.4,5.6,7.8,5.3,1.2}; valarray <

C#中面向对象编程机制之继承学习笔记

继承反应了类和类之间的关系. 世界上很多事物都是有共性的,共性的那一部分我们就抽象为基类,用于派生其它类,这样提高了代码的复用性,使得代码的结构清晰易读,而且易于代码的扩展和维护. C#的继承只能继承自一个基类,这一点不同于C++的继承. C#的继承具有传递性,即B继承自A,C继承自B,则C具有A的所有特性. C#的继承隐式为public的. 假如不在派生类构造器中显示调用一个基类构造器,编译器会自动插入对基类的默认构造器的一个调用,然后才会执行派生类构造器中的代码, 如果基类没有默认的构造器,

【C/C++学院】0822-类型转换函数与构造转换函数/类的继承/类的继承以及区别/继承静态成员与静态函数//继承实现代码重用/单继承QT案例/多继承简介以及实战/Gpu编程

类型转换函数与构造转换函数 #include<iostream> class fushu { public: explicit fushu(int num)//避免隐式转换,引发歧义 { x = num; y = num; } void print() { std::cout << x << "+" << y << "i" << std::endl; } operator int(); //不支

【转载】Javascript原型继承-学习笔记

阮一峰这篇文章写的很好 http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html 笔记如下: 一直很难理解Javascript语言的继承机制. 它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分,全靠一种很奇特的"原型链"(p

《C#高级编程》【第四章】继承 -- 学习笔记

计算机程序,在很大的程度上是为了描述和解决现实问题.在面向对象语言中的类很好的采用了人类思维中抽象和分类的方法,类和对象的关系很好的反映了个体与同类群体的共同特征的关系.但是在诸多共同点之下还是存在着些许差异.于是面向对象语言中设计了继承机制,允许我们在保持原有类特性的基础上,进行拓展.由于类的继承和派生机制的引入,使得代码的重用性和可扩充性大大提高.利用这个机制我们还可以站在巨人的肩膀上就行开发---利用别人写好的类进行扩充,这样又可以提高我们的开发效率.在派生新类的过程一般来说有三个步骤:吸

原型与继承学习笔记1

浅谈对象 面向对象原型链继承这块,应该算是javascript中最难理解的部分了,小弟脑子比较难转弯,也是看了好久视频,博文,慢慢的才有了自己的理解,现在记录一下学习的内容和总结.首先第一节应该说说对象这个东西了,js中对象和其他语言还是有所不同的,现在切入正题,开始浅谈对象. 什么是对象 定义(ECMA-262):无序属性的集合,其属性可以包含基本值.对象或者函数. 通过定义可以看出来,对象是属性的集合,这些属性又会是一个基本值,一个函数或者又是一个新的对象.记住,函数也是对象,了解这点以后原

《代码大全2》学习笔记2

第二部分:创建高质量的代码 第五章:软件构建中的设计 "在大型项目中,设计可能会详细到让编码工作近乎机械化" "在小型项目中,设计可能就是指用伪代码写个类的接口,或者询问旁边的程序员那个模式好,画几个类的关系图" --基本没有经历过大型项目,小型项目描述的过程跟我接触的非常的相似,最多多个设计评审. "当没人知道对一处代码的改动会对其他代码带来什么影响的时候,项目也就停止进展了" --得多复杂,多糟糕的项目才会到这个地步啊,没有体会过. 因为项目

《代码大全2》学习笔记3

第三.四部分--变量.语句 "在声明变量时初始化"--减少未赋值的风险. "尽可能减少变量的存活时间"--感觉如果按照推荐,一般子程序都写的很短,那么这个也就不重要了吧. "一个好记的名字反应的通常是问题,而不是解决方案,是what而不是how" "避免使用相似含义的名字,如果你能让2个变量交换名字还不妨碍理解的话,就说明都要重新改名了."--越功能简单越名字容易相似,哪那么好改啊. "避免使用数字,什么file1,