为什么80%的码农都做不了架构师?>>>   

话说继承:

新类通过调用已存在类的方式获得该类的全部非私有成员和特征的方式叫做继承。其中被继承的类叫做基类(base class,或在Java和C++中叫做父类、超类,super class),调用的类叫做派生类(derived class,或子类,subclass)。继承从面向对象设计的角度来看构成的is-a关系。继承与复合(composition)不同,复合表示一个整体不可缺少的部分。(Chap 11 p.g.343)C++中继承的定义例如:

class TwoDShape : public Shape
class BasePlusCommissionEmployee : public CommisionEmployee

在继承中,若是子类的函数名与父类重名,可以通过使用界定符的方式进行区分,举例如下:

//假设父类中已经存在earnings函数
double BasePlusCommissionEmployee::earnings() const{return getSalary() + CommisionEmployee::earnings();
}

(Chap 11 p.g.368)

另外,在C++中,被定义为final的类不可作为基类被继承。例如:

//此类不可被继承:
class MyClass final{};

应用继承关系,被继承的类不会对于父类产生影响,也避免了代码的引用与重写,符合软件工程的特点。

继承类中父类成员的等级(Chap 11 p.g.345):

  • 继承的子类中,父类成员等级分为公有、受保护以及私有。分为以下三种情况(Chap 11 p.g.371)
  1. 子类中的继承修饰词为public,则父类成员的权限不变。
  2. 子类中的继承修饰词为protected,父类的公有成员变成受保护成员,其余不变。
  3. 子类中的继承修饰词为private,父类所有成员变为私有成员。 注意,友元函数和友元类不被继承。

此外,protected成员变量可以被父类本身、友元函数以及继承的子类调用(Chap 11 p.g.361)。protected变量不通过set和get方法获取变量,因此可以稍稍提高程序运行的速度。然而存在变量易被滥用导致类的状态不稳定以及父类的修改影响其子类这两个问题。(Chap 11 p.g.363 - 364)

子类的构造函数实现中可以像父类构造函数传递参数,例如:

BasePlusCommissionEmployee::BasePlusCommissionEmployee(const string & name,
const string &id, double salary, double tax)
: CommisionEmployee(name, id, salary, tax){}

(Chap 11 p.g.367)

在继承中析构函数与构造函数的运行顺序,可参考楼主文章:《C++拓展笔记2-1:C++析构函数学习心得》,URL: https://my.oschina.net/SamYjy/blog/828146

C++继承中的指针运用

在C++类中,对象可以被赋值给指针变量,指针变量就可以通过指针调用的方式调用对象所对应的类中的相应函数,例如:

//假设commisionEmployee是CommisionEmployee类的一个对象
commisionEmployeePtr = &commisionEmployee;
//同理,
basePlusCommissionEmployee = &basePlusCommissionEmployee;

在C++继承机制中,可以将派生对象直接赋值给基类的指针变量,例如:

commisionEmployeePtr = &basePlusCommissionEmployee;

在虚函数不存在的情形下,C++中指针的类型直接决定了调用函数的类型。比如,假设CommisionEmployee和BasePlusCommissionEmployee都同时存在print方法,则有如下规则:

//调用了CommisionEmployee类的print方法:
commisionEmployeePtr -> print();//调用了BasePlusCommisionEmployee类的print方法:
basePlusCommissionEmployee -> print();
((BasePlusCommissionEmployee *)commissionEmployeePtr) ->print(); //1/*调用BasePlusCommisionEmployee类的setBaseSalary方法:*/
((BasePlusCommissionEmployee *)commissionEmployeePtr)->setBaseSalary(500); //2

备注:其中,1和2两处将基类类的指针通过强制类型转化的方式转化为指向派生类的指针。

虚函数对于指针运用的影响

虚函数是指基类中可能或需要在其派生类中进一步实现的函数,分为普通虚函数和纯虚函数(在函数名后加上等于零)。含有纯虚构函数的类叫做抽象类,它不可被实例化,但是可以被赋予指针变量或地址。普通虚函数不要求派生类必须重载,而纯虚函数要求派生类必须重载。虚函数定义例如:

virtual double earnings() const; //普通虚函数,不一定要求重写
virtual void draw() const = 0; //纯虚函数,要求派生类中被重写,否则派生类也为抽象类

普通虚函数的实现类似正常函数的实现。 虚函数的重写,以函数定义之后加上关键字override结尾,例如:

virtual double earnings() const override; //重写前例earnings函数

需要注意的是,基类中存在虚函数的情况下,指针被赋值的类型决定了调用函数的类型。比如,上述代码中若print函数在基类中被写成了虚函数,则以下代码则变成重写该基函数的子类函数中的print方法了。

//基类中:
virtual void print() const;//子类BasePlusCommisionEmployee中:
virtual void print() const override;//调用BasePlusCommisionEmployee中的print方法:
commisionEmployeePtr -> print();

虚函数存在的类中最好有虚析构函数,否则容易产生用delete删除相应指针时内存无法释放的问题。通过将析构函数定义为virtual,编译器可以自动调用派生类的相应析构函数,达到释放内存的目的。虚析构函数例如:

virtual ~CommissionEmployee(){}

此外,具有虚函数的基类和子类之间指针的转化,还能通过动态转化机制。例如:

//基类指针通过动态转化赋值给子类指针变量
BasePlusCommissionEmployee *derivedPtr = dynamic_cast<BasePlusCommissionEmployee *>(employeePtr);

通过typeid(variable).name()可以获得对象编译时的类型信息(头文件<typeinfo>):

cout << typeid(commissionEmployeePtr).name() << endl;
cout << typeid(((BasePlusCommissionEmployee *)commissionEmployeePtr)).name() << endl;

输出:

参考资料:

  1. 电影旅行敲代码的博客,《dynamic_cast<>操作数必须是多态类型吗》,http://blog.csdn.net/dashuniuniu/article/details/49622237
  2. Paul Deitel & Harvey Deitel, C++11程序设计(英文版)(第2版),本文中C++11括号所表示的资料

转载于:https://my.oschina.net/Samyan/blog/983052

C++学习手记四:继承和多态相关推荐

  1. 判断类型是否继承_【Java学习 | Javase】继承与多态

    整理自:老师课件.<Java核心技术> 继承与多态 继承 概念 父类/超类 所有子集的公共域和公共方法的集合 子类 父类的特殊化,是对公共域和方法在功能.内涵方面的拓展和延伸 object ...

  2. Java学习 day11 (继承与多态)接口、多态

    前言: 前天我们学习了继承,子类可以在父类的基础上重写父类内容,这样很容易误伤很多固定用法,已经写好的类,为了避免这种情况,java提供了final关键字,用来修饰不可改变内容. 我的理解是,类似于我 ...

  3. c++学习笔记之继承和多态

    1.public 继承 class A : public B (1)友元函数不能被继承 (2)protected成员可以被派生类和友元访问 2.派生类 (1)派生类构造函数如果未显式调用基类构造函数, ...

  4. c++学习笔记(13) 继承和多态

    继承:从已有的类派生出新类 基类和派生类 不同的类之间可能有很多共通的属性和行为,这些属性和行为允许在一个类中通用化并被其他类所共享.类C1从类C2扩展而来,则C1称为派生类,C2称为基类,基类也称为 ...

  5. 设计模式学习笔记(四)封装、继承、多态、抽象能解决什么问题?

    面向对象编程及面向对象编程语言的关键就是理解其四大特性:封装.抽象.继承.多态. 1. 封装(Encapsulation) 所谓封装性,封装也叫做信息隐藏或者数据访问保护.类通过暴露有限的访问接口,授 ...

  6. Java第四次作业——面向对象高级特性(继承和多态)

    Java第四次作业--面向对象高级特性(继承和多态) (一)学习总结 1.学习使用思维导图对Java面向对象编程的知识点(封装.继承和多态)进行总结. 2.阅读下面程序,分析是否能编译通过?如果不能, ...

  7. Java第四次作业,面向对象高级特性(继承和多态)

    Java第四次作业-面向对象高级特性(继承和多态) (一)学习总结 1.学习使用思维导图对Java面向对象编程的知识点(封装.继承和多态)进行总结. 2.阅读下面程序,分析是否能编译通过?如果不能,说 ...

  8. 学习笔记:C++进阶【继承、多态、二叉树进阶、map和set、哈希、C++11、异常、智能指针、特殊类设计、C++的类型转换】

    文章目录 前言 一.继承 1. 继承的概念及定义 1.1 继承的概念 1.2 继承的定义 1.2.1 定义格式 1.2.2 继承关系和访问限定符 1.2.3 继承基类成员访问方式的变化 2. 基类和派 ...

  9. c++学习总结(4):继承与多态

    C++学习总结(4):继承与多态 一.继承和派生 二.子类与父类之间的构造函数与析构函数 三.子类与父类成员重名 四.多继承 五.虚继承 virtual 六.多态 七.虚析构函数 八.重载,重写,重定 ...

最新文章

  1. Self Ogannizing Maps(SOM)自组织映射
  2. 转 ofbiz的webservice接口提供(2)-数据类型的局限性
  3. 使用ES6的Promise完美解决回调地狱
  4. MyBatis(三)——动态SQL
  5. python爬虫导入数据库_python爬虫爬下来的数据怎么导入到MySQL
  6. Linux系统编程——线程(1)
  7. Dotnet 6.0 深度探索(一)
  8. [vue] 请描述下vue的生命周期是什么?
  9. 声明为指针,定义为数组,声明为数组,定义为指针
  10. 并联串联混合的电压和电流_高考物理常考实验之电流表改装电压表怎么串联电阻...
  11. 有限状态机的C++实现(2)-bayonet开源网络服务器框架
  12. ASP.NET C# 实现钉钉签名算法
  13. linux+ipv6免流量下载,如何限定apt-get使用IPv4或IPv6协议下载
  14. nod32系统更新服务器,Nod32官方升级服务器列表
  15. 程序员也要学英语——数词攻略
  16. k8s 使用HPA 进行弹性扩容pod节点,
  17. 常见的HTTP请求方法
  18. python获取pdf页数_Python读取pdf页面的一部分
  19. 决胜最后一公里 外卖O2O须达信息化标准
  20. 数组去重,对象去重,数组对象去重

热门文章

  1. python add configuration_idea 中add configuration
  2. 【Android UI】TextView的垂直方向概念之top,bottom,ascent,descent,baseline
  3. python 权限控制 linux_16linux的acl的控制权限的介绍
  4. list 去重_测试面试题集Python列表去重
  5. 20165235实验四 Android程序设计
  6. MySQL 单表百万数据记录分页性能优化
  7. android用于打开各种文件的intent
  8. Web移动端Fixed布局的解决方案
  9. IDEA统一设置编码为utf-8编码及tomcat 乱码问题的解决
  10. java 异常的捕获及处理