C++对象模型复习
一:对象模型
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无需调整,因为他们起始位置是一样的。
有三种情况,第二或后继的基类会影响对虚函数的支持:
- 通过一个指向第二基类的指针,调用派生类虚函数(指针必须后移)。
- 通过一个派生类的指针,调用第二个基类中一个继承而来的virtual function,此情形派生类指针必须再次调整,以指向第二个基类子对象。
- 第三种情况发生于一个语言扩充性质之下,允许一个虚函数返回值类型发生变化,可能是基类类型,或者派生类类型。比如base* pb=pb->clone(),该函数返回值为derived*类型,所以此处必须调整offset。
五
六
七
1.为什么catch字句的异常声明通常被声明为引用?
可以避免由异常对象到catch字句中的对象的拷贝,特别是对象比较大时。
能确保catch字句对异常对象的修改能再次抛出
能确保正确地调用与异常类型相关联的虚拟函数,避免对象切割
异常对象的声明周期?
产生:throw className()时产生
销毁:该异常最后一个catch字句退出时销毁
注意:因为一场可能在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++对象模型复习的更多相关文章
- C++ 系列:C++ 对象模型
1 何为C++对象模型 C++对象模型可以概括为以下2部分: 1.语言中直接支持面向对象程序设计的部分: 2.对于各种支持的底层实现机制 语言中直接支持面向对象程序设计的部分,如构造函数.析 ...
- JS复习--更新结束
js复习-01---03 一 JS简介 1,文档对象模型 2,浏览器对象模型 二 在HTML中使用JS 1,在html中使用<script></script>标签 2,引入外部 ...
- [Java面试一]面试复习大纲.
一.Java基础部分 (搞定所有技术之后才考虑复习的技术点) 1.数组中的排序问题(笔试或者机试,前者可能性更大) 2.面向对象的理解 3.集合相关的问题,比如hashmap跟hashtable的区别 ...
- 复习面向对象的OOA、OOD、OOP
复习 OOA.OOD.OOP OOA Object-Oriented Analysis:面向对象分析方法 是在一个系统的开发过程中进行了系统业务调查以后,依照面向对象的思想来分析问题. OOA与结构化 ...
- java复习(1)---java与C++区别
[系列说明]java复习系列适宜有过java学习或C++基础或了解java初步知识的人阅读,目的是为了帮助学习过java但是好久没用已经遗忘了的童鞋快速捡起来.或者教给想快速学习java的童鞋如何应用 ...
- Javaweb学习笔记——(十五)—————— sql复习
sql复习 数据库管理系统(DBMS)的概述 1.什么是DBMS:数据的仓库 *方便查询 *可存储的数据量大 *保证数据的完整.一致 *安全可靠 2.DBMS的发展:今天主流数据库为关系型数据库管理系 ...
- HIBERNATE知识复习记录3-关联关系
先上一张图,关于几种关系映射: 抄一段解释: 基本映射是对一个实体进行映射,关联映射就是处理多个实体之间的关系,将关联关系映射到数据库中,所谓的关联关系在对象模型中有一个或多个引用.关联关系分为上述七 ...
- Hibernate复习之Hibernate基本介绍
众所周知.眼下流行的面向对象的对象关系映射的Java持久层框架有MyBatis和Hibernate.他们都是对象关系映射ORM. 解决的主要问题就是对象-关系的映射.域模型和关系模型都分别建立在概念模 ...
- JS---part5 课程介绍 & part4 复习
part5 课程介绍 另一个定时器 第一个定时器的小案例----练习 封装动画函数----------匀速的动画函数,过渡到=======>缓动的动画函数 简单的轮播图 左右焦点的轮播图 无缝连 ...
随机推荐
- js备战春招の四のDOM
通过js查找html元素的三种方法: 1.通过id找到html元素. 2.通过标签名找到html元素. 3.通过类名找到html元素. DOM HTML document.write(); 直接写入h ...
- windows 10, v1903 正式版下载
一.简体中文版 cn_windows_10_business_editions_version_1903_x64_dvd_e001dd2c.iso sha1:bc6176bee6130 ...
- Markdown语法进阶
tip:基本都是通过html格式实现的. 插入音频 插入音乐 在网易云音乐里找生成外连接,复制过来就OK了,可惜的是很多都不能生成外联连接.如果想自动播放,可以把auto改成1. 插入视频 直接引用在 ...
- c# linq lambda 去重,排序,取最高纪录。
----------------------------------------------------.对基础类型排序 方法一: 调用sort方法,如果需要降序,进行反转: List<int& ...
- 近视BFC
首先按照常规解释一下名词,BFC(Block formatting context)直译为"块级格式化上下文".一个独立的渲染区域,只有Block-level box参与, 它规定 ...
- vue--transition-group
1.为什么要使用<transition-group> <transition></transition>是vue封装的过渡组件 <transition nam ...
- 关于Ocelot和Consul 实现GateWay(网关) 服务注册 负载均衡等方面
Ocelot 路由 请求聚合 服务发现 认证 鉴权 限流熔断 内置负载均衡器 Consul 自动服务发现 健康检查 通过Ocelot搭建API网关 服务注册 负载均衡 1. ...
- 环境准备—之—linux下安装svn--开机自启--及format权限问题
借鉴自 http://www.cnblogs.com/liuxianan/p/linux_install_svn_server.html 这个很详细,但不是我的风格 https://blog.csdn ...
- Spring Boot属性文件配置文档(全部)
This sample file is meant as a guide only. Do not copy/paste the entire content into your applicatio ...
- pip使用国内源
对于Python开发用户来讲,PIP安装软件包是家常便饭.但国外的源下载速度实在太慢,浪费时间.而且经常出现下载后安装出错问题.所以把PIP安装源替换成国内镜像,可以大幅提升下载速度,还可以提高安装成 ...