一:对象模型

C++面向对象的实现,相对于C耗费成本是由virutal引起的。包括

  • virtual function机制,用来支持执行期绑定。
  • virutal base class 虚基类机制,以实现共享虚基类的subobject

此外还有多重继承下,发生在其第二或后继派生类之间的转换。

C++对象模型,所有非静态数据成员存储在对象本身中,所有的静态数据成员,成员函数(包括静态与非静态)都置于对象之外。虚函数的支持是在每个class内部维护一个vptr指向vtbl,vtbl存放所有虚函数指针。vptr的设定和重置都由每一个class的构造函数/析构函数/拷贝分配函数自动完成。每一个typeinfo也放在vtbl之中(用来支持RTTI),vtbl之中还有virtual base subobject的offset值。

主要有三种方法支持多态:(1)基类使用引用或指针接收派生类。(2)可调用虚函数触发多态。(3)经由dynamic_cast和typeid运算符。

当一个基类对象被直接初始化为一个派生类对象时,派生类对象就会被切割,仅剩基类类型大小的内存。

总结:

总而言之,多态是一种威力强大的设计机制,允许通过将派生类的指针赋给基类指针,让基类可以根据赋值给它的子类的特性以不同的方式运作。需要付出的代价就是额外的间接性,包括虚表和RTTI两方面。

二:构造函数语意学

四种情况下编译器自动合成trival构造函数:

1.包含带有默认构造函数的对象成员的类 2. 继承自带有默认构造函数的基类的类 3.带有虚函数的类 4.带有一个虚基类的类

拷贝构造函数同理,否则执行默认位逐次拷贝。

NRV优化不必说。

成员初始化列表必须使用的情况:1.有const成员 2.有引用类型成员 3.有没有默认构造函数的成员对象 4.基类对象没有默认构造函数

三:Data语意学

影响C++类的大小的三个因素:

  • 支持特殊功能所带来的额外负担(对各种virtual的支持)
  • 编译器对特殊情况的优化处理(空class)
  • 内存对齐

一般对象的布局顺序为:vptr、基类成员(按声明顺序)、自身数据成员、虚基类数据成员(按声明顺序)

四:Function语意学

C++支持三种类型成员函数,分别是static、nonstatic、virtual。

非静态成员函数:和非成员函数由相同的效率,因为编译器内部会将其转换为非静态成员函数,加上this指针作为额外参数。此外还要额外对函数的名称进行处理。

虚拟成员函数p->function转换为(*p->vptr[1])(p),引入虚表下表。

静态成员函数实际上相当于全局函数。不能够存取类中非静态成员,不能调用非静态成员函数。不能够声明为const、voliatle或virtual。它不需要经由对象调用,当然,通过对象调用也被允许。

消极多态与积极多态:

Point ptr = new Point3d    //Point3d继承自Point

在这种情况下,多态可以在编译期完成(虚基类情况除外),因此被称作消极多态(没有进行虚函数的调用)。相对于消极多态,则有积极多态--指向的对象类型需要在执行期才能决定。积极多态的例子如虚函数和RTTI:

//例1,虚函数的调用
ptr->z();
//例2,RTTI的应用
if(Point3d *p = dynamic_cast<Point3d*>(ptr))
return p->z();

虚基类子对象为什么是运行时确定的,而不是编译器? 因为虚基类的构造函数在继承体系中被编译器压制到了最派生类才构造,所以集成体系中间的类不能再编译器确定虚基类子对象的位置。因为它下面可能还有多层继承。所以要引入一个间接性,为虚继承体系中每个class引入一个虚基类子对象offset,在运行时填充该offset。

在多重继承中支持虚函数,其复杂度围绕在第二个或后继基类身上,以及“必须调整this指针这一点”。多重继承中调整this指针(注意没说虚函数):比如对于base *pbase = new derived(这里没有多态),新的derived对象以指向base subobject。如果没有这样的调整,指针的任何非多态运用都将失败,向base->data_base,存取操作会失败!或者delete base,这个操作执行时又必须把this指针指到头部,因为要析构的大小是derived对象大小。这些操作必须在执行期完成,也就是this指针跳跃的这些offset必须指到,其实会存于vtbl之中。如果base是派生类的最基类,那么this无需调整,因为他们起始位置是一样的。

有三种情况,第二或后继的基类会影响对虚函数的支持:

  1. 通过一个指向第二基类的指针,调用派生类虚函数(指针必须后移)。
  2. 通过一个派生类的指针,调用第二个基类中一个继承而来的virtual function,此情形派生类指针必须再次调整,以指向第二个基类子对象。
  3. 第三种情况发生于一个语言扩充性质之下,允许一个虚函数返回值类型发生变化,可能是基类类型,或者派生类类型。比如base* pb=pb->clone(),该函数返回值为derived*类型,所以此处必须调整offset。

1.为什么catch字句的异常声明通常被声明为引用?

  1. 可以避免由异常对象到catch字句中的对象的拷贝,特别是对象比较大时。

  2. 能确保catch字句对异常对象的修改能再次抛出

  3. 能确保正确地调用与异常类型相关联的虚拟函数,避免对象切割

  4. 异常对象的声明周期?

  5. 产生:throw className()时产生

  6. 销毁:该异常最后一个catch字句退出时销毁

  7. 注意:因为一场可能在catch子句中重新被抛出,所以在到达最后一个处理该异常的catch子句之前,异常对象是不能销毁的。

RTTI:

  • RTTI只支持多态类,也就是说没有定义虚函数的类是不能进行RTTI的
  • 对指针的dynamic_cast失败时会返回NULL,对引用的话,失败会抛出bad_cast_exception.
  • typeid可以放回const type_info&,用以获取类型信息。

关于1是因为RTTI的实现时通过vptr来获取存储在虚函数表中的type_info*,事实上为非多态类提供RTTI,也没有多大意义。2的原因在于指针可以被赋值为0,以表示no object,但是引用不行。关于3,UI然第一点指出RTTI只支持多肽类,但typeid和typeinfo同样可适用于内建类型及所有非多态类。与多态类的差别在于,非多态类的type_info对象是静态取得,**所以不能叫“执行期类型识”。

dynamic_cast主要用于类层次之间的上行装换和下行转换,还可以用于类之间的交叉转换。上行转换时,static_cast是安全的。在进行下行转换时,dynamic_cast有类型检查的功能,比static_cast更安全:

#include <iostream>
#include <assert.h> class base {
public:
virtual void fun() { std::cout<<"base"<<std::endl; } //去掉virtual dynamic_cast会编译失败
}; class derived : public base {
public:
char* str[100];
}; void test(base* b)
{
derived* d1 = static_cast<derived*>(b);
//d1->str[1] = "hello"; //使用static_cast不会类型检查,如果b指针真得是derived*类型此处就没问题,如果b实际上就是base类型,此处段错误
derived* d2 = dynamic_cast<derived*>(b);
assert(d2 == NULL); //使用dynamic_cast,如果b只是base*类型,上一句强转称为derived*类型会失败,d2会返回NULL。
} int main()
{
base *b;
test(b);
return 0;
}

另外,dynamic_cast还支持交叉转化(cross cast),也就是继承体系中统一层级的对象之间的转换。而使用static_cast这种无关连的类的转换会编译不通过。

#include <iostream>
class A
{
public:
int m_iNum;
virtual void f(){}
}; class B:public A
{
}; class D:public A
{
}; void foo()
{
B* pb = new B;
pb->m_iNum = 100;
//D* pd1 = static_cast<D*>(pb); //compile error
//D* pd2 = dynamic_cast<D*>(pb);//pd2isNULL
delete pb;
} int main()
{
foo();
}

C++对象模型复习的更多相关文章

  1. C++ 系列:C++ 对象模型

    1      何为C++对象模型 C++对象模型可以概括为以下2部分: 1.语言中直接支持面向对象程序设计的部分: 2.对于各种支持的底层实现机制 语言中直接支持面向对象程序设计的部分,如构造函数.析 ...

  2. JS复习--更新结束

    js复习-01---03 一 JS简介 1,文档对象模型 2,浏览器对象模型 二 在HTML中使用JS 1,在html中使用<script></script>标签 2,引入外部 ...

  3. [Java面试一]面试复习大纲.

    一.Java基础部分 (搞定所有技术之后才考虑复习的技术点) 1.数组中的排序问题(笔试或者机试,前者可能性更大) 2.面向对象的理解 3.集合相关的问题,比如hashmap跟hashtable的区别 ...

  4. 复习面向对象的OOA、OOD、OOP

    复习 OOA.OOD.OOP OOA Object-Oriented Analysis:面向对象分析方法 是在一个系统的开发过程中进行了系统业务调查以后,依照面向对象的思想来分析问题. OOA与结构化 ...

  5. java复习(1)---java与C++区别

    [系列说明]java复习系列适宜有过java学习或C++基础或了解java初步知识的人阅读,目的是为了帮助学习过java但是好久没用已经遗忘了的童鞋快速捡起来.或者教给想快速学习java的童鞋如何应用 ...

  6. Javaweb学习笔记——(十五)—————— sql复习

    sql复习 数据库管理系统(DBMS)的概述 1.什么是DBMS:数据的仓库 *方便查询 *可存储的数据量大 *保证数据的完整.一致 *安全可靠 2.DBMS的发展:今天主流数据库为关系型数据库管理系 ...

  7. HIBERNATE知识复习记录3-关联关系

    先上一张图,关于几种关系映射: 抄一段解释: 基本映射是对一个实体进行映射,关联映射就是处理多个实体之间的关系,将关联关系映射到数据库中,所谓的关联关系在对象模型中有一个或多个引用.关联关系分为上述七 ...

  8. Hibernate复习之Hibernate基本介绍

    众所周知.眼下流行的面向对象的对象关系映射的Java持久层框架有MyBatis和Hibernate.他们都是对象关系映射ORM. 解决的主要问题就是对象-关系的映射.域模型和关系模型都分别建立在概念模 ...

  9. JS---part5 课程介绍 & part4 复习

    part5 课程介绍 另一个定时器 第一个定时器的小案例----练习 封装动画函数----------匀速的动画函数,过渡到=======>缓动的动画函数 简单的轮播图 左右焦点的轮播图 无缝连 ...

随机推荐

  1. 论文笔记:DARTS: Differentiable Architecture Search

    DARTS: Differentiable Architecture Search 2019-03-19 10:04:26accepted by ICLR 2019 Paper:https://arx ...

  2. showdoc 自动脚本安装

    ========================== showdoc 简介==========================在线文档管理系统很多, 比如阿里的语雀.腾讯的 TAPD 平台也包括文档管 ...

  3. 生信工具汇总--OMICtools

    各种生信工具: https://omictools.com/

  4. vue ui 启动,浏览器报错Unexpected token <

    可能的解决办法: 选择清空缓存并硬性重新加载页面. 如果不行,全局卸载@vue/cli,重新安装.

  5. 1047 Integer Inquiry

    String 大数加法模板 #include<stdio.h> #include<string> #include<iostream> using namespac ...

  6. mac 开启ntfs 权限

    原文: https://zhuanlan.zhihu.com/p/29542892 参考: https://bbs.feng.com/read-htm-tid-9932031.html 其实最早在OS ...

  7. java中捕获Oracle异常

    try{ } catch (Exception e){ String msg=.getMessage(): int index= msg. toUpperCase(). indexOf("O ...

  8. jmeter的安装和配置

    jmeter环境配置 Java 8 安装 正常安装,一路默认就好,记住安装路径,配置环境变量时用得到.默认安装路径:C:\Program Files\Java\jdk1.8.0_91. 安装好之后会有 ...

  9. .NET Core WEB API使用Swagger生成在线接口文档

    1项目引用Swashbuckle.AspNetCore程序集和Microsoft.Extensions.PlatformAbstractions程序集 右击项目打开"管理NuGet程序包.. ...

  10. 对XML里的属性或元素进行模糊搜索的方法

    最近发现几个贴子都是问关于对XML的属性或元素进行模糊搜索的方法,在此发出代码片段示例,希望能够对你有所帮助:) 示例XML private var xml:XML=<employees> ...