C++第六天_车晋强的博客-程序员秘密

技术标签: danei  

十二、多重继承与钻石继承
1.名字冲突问题
用过类名+作用域限定
A
  foo
B
  foo
C : A, B
C c;
c.A::foo
c.B::foo
汇聚替代:在子类中提供对有冲突标识符的隐藏版本,在该隐藏版本中通过重载等机制,指明调用的是哪个基类中的。
2.钻石继承问题
钻石继承:子类继承自多个基类,而这些基类又源自一个共同的基类。
       A
      / \
     B   C
      \ /
       D
问题:公共基类子对象在每个中间子类中各有一个实例,因此通过不同继承路径访问公共基类子对象中的数据会有不一致的问题。
解决:通过虚继承,使公共基类子对象在最终子类对象中只有一0份实例,而所有中间子类对象共享该实例。
虚继承:virtual、最终子类的构造函数可能需要显式指明公共基类子对象的构造方式。
十三、虚函数与多态
1.虚函数与多态的基本概念
       图形-位置、绘制
      /    \
  矩形      圆形
  长,宽    半径
  绘制      绘制
在基类中将一个成员函数声明为虚函数(在返回类型前面加上virtual关键字),其子类中的同原型成员函数就也成为虚函数,并且对基类中的版本形成覆盖。此时,通过一个指向子类对象的基类指针,或者引用子类对象的基类引用,调用该虚函数,实际被调用的是子类中的覆盖版本。这种语法现象被称为多态。
虚函数——覆盖——多态。
2.虚函数覆盖的限制
1)基类中的成员函数必须被声明为虚函数,子类中的成员函数与基类中虚函数的函数名、形参表、常属性完全相同。
2)如果基类中虚函数的返回类型是基本类型,那么子类中覆盖版本的返回类型必须与基类版本完全相同。
3)如果基类中虚函数的返回类型是类类型的指针或引用,那么子类中覆盖版本的返回类型也可以是基类版本返回类型的子类。
4)子类中的覆盖版本不能比基类中的虚函数抛出更多的异常。
5)子类中覆盖版本的访控属性与基类无关。
3.注意严格区分重载、隐藏和覆盖。
class Visitor {
public:
  virtual bool visit (int credit); // A
  virtual bool visit (double cash); // B
};
class ValidVisitor : public Visitor {
public:
  bool visit (int credit); // C
};
class MyValidVisitor : public ValidVisitor {
public:
  bool visit (double cash); // D
};
class Dumy : public Visitor {
public:
  void visit (int credit); // E
};
B和A:重载
C和A:覆盖
C和B:隐藏
D和C:隐藏
D和B:覆盖
E和A:错误的覆盖
4.纯虚函数、抽象类与纯抽象类
纯虚函数:在基类中被定义为如下形式的成员函数:
virtual 返回类型 成员函数名 (形参表)=0;
被称为纯虚函数。
抽象类:至少包含一个纯虚函数的类。抽象类不能被实例化为对象。抽象类的子类如果没有对基类中所有的纯虚函数提供覆盖定义,那么该子类也是抽象类。
纯抽象类:完全由纯虚函数(除了构造和析构函数)组成的抽象类。<接口>
虚基类是从虚继承来的,为了解决钻石继承问题。
5.虚函数表与动态绑定
虚函数表是一个存放虚函数地址的函数指针数组。每个由包含虚函数的类所创建的对象中都有一个指向该虚函数表的指针。当通过指向子类对象的基类指针,或者引用子类对象的基类引用调用基类中的虚函数时,实际上是根据该指针或引用实际指向的对象中的虚函数表获取函数地址并调用的。
//
vftbl.cpp
/
对于A的子类B:
A* pa = new B (...);
当前编译器看到
pa -> foo ();
并不直接生成函数调用代码,相反它会自动生成一些列操作指令,完成以下动作:
a)明确pa的类型及其所指向的对象;
b)从pa所指向的对象中提取虚函数表,并找到与foo()函数相对应的函数地址。
c)根据所找到的虚函数地址,调用之。
以上三步操作均在运行阶段完成,故谓之动态绑定。
6.多态的前提和限制
多态=虚函数+指针或引用
在基类的构造函数和析构函数中调用虚函数,没有多态性,实际调用的永远是基类版本。
十四、运行时类型信息——RTTI
1.动态类型转换:dynamic_cast
在运行期对指针实际指向的类型(应具有多态性)做检查,以返回NULL表示转换失败。
2.静态类型转换:static_cast
在转换源类型和目标类型之间只要有一个方向上可以做隐式转换,那么在另一个方向上就可以做静态转换。以编译错误的形式表示转换失败。
3.重解释类型转换:reinterpret_cast
无论在编译期还是运行期均不做任何检查,使用时要十分慎重。
4.获取类型信息
typeid ()运算符返回值是一个typeinfo类型(声明在typeinfo的头文件中)的对象。其中包括一个name的成员函数,通过该函数可以获得类型的字面名称。同时typeinfo对象还可以用于比较两个类型是否相同或不同。
typeid可以获取指针所指向对象的实际类型,前提是该类型应具有多态性。
十五、虚析构函数
1.将基类的析构函数定义为虚函数。delete一个指向子类对象的基类指针将导致子类类型的析构函数被调用,该函数在释放完子类对象特有的资源之后,自动调用基类类型的析构函数,完整其基类部分的释放。
2.如果一个类中存在虚函数,往往意味着该类可以多态方式被使用,因此该类的析构函数就应该被定义为虚函数。
思考:
              定义为虚函数
全局函数      No
普通成员函数  Yes
静态成员函数  No
构造函数      No
析构函数      Yes
操作符函数
  成员        Yes
  友元        No
-----------------
class DocParser {
public:
  void parse (...) {
    ...
    onRect (...);
    ...
    onText (...);
    ...
    onImage (...);
  }
  virtual void onRect(...)=0;
  virtual void onText(...)=0;
  virtual void onImage(..)=0;
};
class DocRender : public DocParser {
  void onRect(...) {...};
  void onText(...) {...};
  void onImage(..) {...};
};
DocRender dr (...);
dr.parse ();
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/chejinqiang/article/details/44080849

智能推荐

element使用tabs+navmenu完成后台首页菜单导航联动_element 导航菜单和标签页联动_williamyi74的博客-程序员秘密

首先上图给大家看看实现效果:然后直接上核心代码: &lt;!-- 左侧菜单栏 --&gt; &lt;div class="aside"&gt; &lt;el-menu class="menu" :default-active="$route.path" @open="handleOpen" @close="handleClose" router

在 vue-cli3.x 项目中引用自定义的 .js 文件_vue3 中自定义js文件的写法_itBellah的博客-程序员秘密

1\ 项目目录结构2\ 引用如想在 about.vue 中调用 about.js里定义的函数第一步,写好自定义方法第二步,在需要的组件中通过 import 引入,并在需要的地方调用第三步,查看结果,已正确引入3\ 拓展,当定义了多个方法时输出结果4\ 或者通过以下方法引入多个方法...

Unity使用Mesh Render画线_meshrender_程序员正茂的博客-程序员秘密

 using System.Collections.Generic;using UnityEngine;public class TestScript : MonoBehaviour { // Use this for initialization void Start () { GameObject obj = new GameObject(&quot;cube&quot;);...

ServletContainerSessionManager类_iteye_10899的博客-程序员秘密

ServletContainerSessionManager类主要定义了,它实现了WebSessionManager接口,现对其解析如下:1.WebSessionManager接口可以参考WebSessionManager接口源码解析,里面只有一个方法, 定义了session是否由servletcontainer管理。2.ServletContainerSessionManager...

DSLR-Quality Photos on Mobile Devices with Deep Convolutional Networks_zmm_mohua的博客-程序员秘密

DSLR-Quality Photos on Mobile Devices with Deep Convolutional Networks源码:https://github.com/aiff22/DPED论文简介:数据集:方法:实验及评估:总结:

pie求指点_与渺小的博客-程序员秘密

最后输出的时候用printf("%.4f\n",midpi);就通过了,而用printf("%.4f\n",midpi);就过了,不知道为什么,我的pi和mid用的是double定义的!求大佬指导!//AC代码#include&lt;iostream&gt;#include&lt;cstdio&gt;#include&lt;algorithm&gt;#include&lt;cmath&gt;using namespace std;const double pi=acos(-1.0);int

随便推点

盘点前端开发常用的几款编辑器_hbuilderx(webstorm_weixin_58384302的博客-程序员秘密

1. VScode(最好用)Visual Studio Code,vscode同样也是一个轻量级但功能强大的跨平台的文本编辑器,可在桌面运行,适用于Windows,MACOS,和Linux平台。它内置了对JavaScript,TypeScript和Node.js的支持,并且具有丰富的其他语言(如C++,C#,Java,Python,PHP,Go)和运行时(如.NET和Unity)的扩展生态系统。2.Sublime TextSublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图..

maven 引入qrcode.jar_qrcode maven_修心猿的博客-程序员秘密

mvn install:install-file -Dfile=e:\QRCode.jar -DgroupId=QRCode -DartifactId=QRCode -Dversion=3.0 -Dpackaging=jar  3,在pom.xml中增加如下语句  &amp;lt;dependency&amp;gt; &amp;lt;groupId&amp;gt;QRCode&amp;lt;/groupId&amp;gt; &amp;lt;arti...

mac上使用VSCode svn插件报错不能更新`提交 的问题_cmdszh的博客-程序员秘密

报错如下:Commit failed (details follow):Unable to connect to a repository at URL ‘https://xxx.xxx.xxx.xxx/svn/xxx/1_client/trunk/xxx’Server SSL certificate verification failed: certificate issued for a...

解决:自定义AlertDialog设置宽满屏时显示却有margin属性_不强何以成标杆的博客-程序员秘密

这个问题研究了好久,又是设宽的属性又设其他的,都不管用,但最后就一句话解决了问题。如下: 前提如下: 先用 AlertDialog dialog = builder.create(); 获取到这个dialog。然后需要在 dialog.show(); 下面加这么一句代码。dialog.getWindow().setBackgroundDrawable(null);试试?已经...

MySql 外键为空(null)_mysql外键为空_万里归来少年心的博客-程序员秘密

本文通过实例,验证了MySql 外键可以为空(null)。1.建表 商品表create table goods(id int primary key)ENGINE = INNODB; 订单表create table orders(id int,goodid int ,foreign key(goodid) references goods(id...

Docker+UPX 构建更小的镜像_weixin_34075551的博客-程序员秘密

无论是在我们的生产环境或测试环境中,一旦涉及到docker pull和push的时候,我们都迫切希望Docker镜像是一个非常小的file,一方面在网络带宽有限的情况下,image的size越小下载所付出的时间代价就越小,另一方面image始终是一个文件,size对存储空间是有一定影响的,看来这是个提高生产力的问题,那么我们如何去构建一...

推荐文章

热门文章

相关标签