`
russelltao
  • 浏览: 152081 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

生成一个C++对象的成本

 
阅读更多

最近两年C用得多了,C++有些生疏,又常常用PYTHON,或者阅读些JAVA的代码,感觉C的开发者们由于C语言在软件工程上的先天缺陷,导致开发效率不高,所以决定拿出C++来看看用用,准备把libevent封装出一个类ACE的C++实现,首先来复读下C++对象模型吧。要了解new一个object的成本,最主要的就是知道,编译器会给对象分配多少内存,知道C++的对象模型无疑就了解这一点了。


如果要研究C++的对象模型,大家潜意识都想知道的是,C++比C好在哪里?又比C差在哪里?

我们主要就是想从C++的对象模型里找到后一个答案。前一个答案在软件工程中是毫无疑义的,面向对象的优越性要比C语言里一堆数据结构+和一堆可能与它们相关的函数,可读性、可用性好很好,对开发大型软件工程,需要几百人开发一个项目来说,C++好太多了。看看JAVA或者python程序员们,他们为什么可以一直站在巨人的肩膀上,想完成任何一个功能都超级方便的调用大师们以前写好的package/API,借用各种设计模式,应用级别程序员们可以非常EASY的使用复杂的设计,一些只有高级C程序员才能掌握的东东。当然,JAVA的很多特性也导致不适应核心服务器的开发,比如它的垃圾回收机制。


OK,闲话少叙,在看对象模型前,先看几个C++与C语言的典型不同之处。

1、自然是类的定义了,最大的改变就是类把数据结构与方法捆到一起了,可读性上提升巨大。对成员变量和成员方法,有5种类型:static member, nonstatic member, static function, nonstatic function, virtual function.

2、继承,这里很有许多细节了,核心解决问题就是动态绑定,也就是virtual关键字。virtual出现的唯一原因就是为了解决继承机制,否则struct里引入方法就足够了,class出现就是为了这。virtual关键字解决了子类实例和父类实例的一些特殊关系,考虑以下场景:软件工程中,很喜欢每个模块专注于自己的事,尽量忽略与自己无关的实现,这样,很可能会用一个父类指针,该指针太可能指向多种不同的子类了,但是现在,使用这个抽象父类指针的模块不想关注细节,当它调用对象的某个方法时,到底是调用父类的方法还是子类的方法呢?动态绑定这个特性就是,开发者可以决定这一点,当你用virtual关键字申明父类方法时,如果子类重定义了该方法,如果这个指针实际指向的是某子类对象,那么调用的方法一定是该子类方法的实现。


举个例子吧,就像什么析构函数总喜欢写成virtual?这个例子应该容易说明virtual的玩法。一段简单的代码:

#include <iostream>
using namespace std;


class Father
{
public:
	int m_fMember;
	Father(){m_fMember=1;}
	~Father(){cout<<m_fMember<<endl;}
};


class Child : public Father{
public:
	int m_cMember;
	Child(){m_cMember=2;}
	~Child(){cout<<m_cMember<<endl;}
};


int main(int argc, char** argv)
{
	Father* pObj1 = new Child();
	delete pObj1;
	Child* pObj2 = new Child();
	delete pObj2;	
	return 0;
}

这段代码的结果是1 2 1,啥意思呢?就是说,如果不用virtual函数,是没有执行期绑定一说的,比如pObj1这个指针,其实它是Child对象,但是在释放时,~Child()方法并没有被调用,仅调用了~Father方法。为什么呢?因为没有用virtual,就是编译期绑定,当你在编译时gcc/g++只知道pObj1是个Father对象,所以在delete时就去调用Father的析构了。而如果定义成virtual ~Father时,结果就是一定会析构Child,这就是为什么析构函数都要用virtual,因为没人知道会不会有子类继承,否则一旦继承,发生这样的事,析构函数里万一释放了些资源,比如SOCKET,比如memory,那就是资源泄露了。


那么以上,C++对象模型是怎么做到的呢?画张象征性的图吧。先定义一个类,再看看它的内存布局:

class Father
{
public:
	int m_fMember;
	static int m_sMember;
	static void testSFunc(){}
	void testFunc(){}
	virtual void testVFunc(){}
	Father(){m_fMember=1;}
	virtual ~Father(){cout<<m_fMember<<endl;}
};

我们生成一个Father对象,看看它的的内存布局是啥样的(同志们,这只是近似存储布局图,没有把编译和运行的差别放上去,下篇再讲这个):


这里大家明白了吧?即使一个Child对象在编译时被赋为Father类型,但是实际调用时,virtual方法会被单独的拎出来,在vtbl中指向实际的实现,所以,该对象在delete时会调用Child的析构函数,而如果你像上面例子那样,析构方法不使用virtual,将会用到上图中的最后一个指针,指向类成员函数里,这样就不是执行期绑定了。


剩下的static成员(还有所有的正常成员函数),都是与对象实例无关的内存布局。这样,其实如果不使用virtual,C++比之C并没有增加成本,尽可放心使用。



分享到:
评论

相关推荐

    深度探索C++对象模型(清晰版).pdf

    书中涵盖了C++对象模型的语意暗示,并指出这个模型是如何影响你的程序的。 对于C++底层机制感兴趣的读者,这必然是一本让你大呼过瘾的绝妙好书。如果你是一位C++程序员,渴望对于底层知识获得一个完整的了解,那么...

    深度探索C++对象模型 PDF中文清晰版

    《深度探索C++对象模型》专注于C++面向对象程序设计的底层机制,包括结构式语意、临时性对象的生成、封装、继承,以及虚拟——虚拟函数和虚拟继承。这本书让你知道:一旦你能够了解底层实现模型,你的程序代码将获得...

    深入探索C++对象模型-总结笔记.pdf

    总结笔记,关于侯捷翻译的《深入探索c++对象模型》的笔记 作者Lippman参与设计了全世界第一套C++编译程序cfront,这本书就是一位伟大...如果你是一位C++程序员,渴望对于底层知识获得一个完整的了解,那么本书正适合你

    深度探索C++对象模型(侯捷译)

    Inside The C++ Object Model专注于C++对象导向程序设计的底层机制,包括结构式语意、暂时性对象的生成、封装、继承,以及虚拟——虚拟函数和虚拟继承。这本书让你知道:一旦你能够了解底层实现模型,你的程序代码将...

    深度探索C++对象模型2012版.rar

    作者Lippman参与设计了全世界第一套C++编译程序cfront,这本书就是一...书中涵盖了C++对象模型的语意暗示,并指出这个模型是如何影响你的程序的。 对于C++底层机制感兴趣的读者,这必然是一本让你大呼过瘾的绝妙好书。

    深度探索c++对象模型

    Inside The C++ Object Model专注于C++对象导向程序设计的底层机制,包括结构式语意、暂时性对象的生成、封装、继承,以及虚拟——虚拟函数和虚拟继承。这本书让你知道:一旦你能够了解底层实现模型,你的程序代码将...

    深度探索C++对象模型(简)

    Inside The C++ Object Model专注于C++对象导向程序设计的底层机制,包括结构式语意、暂时性对象的生成、封装、继承,以及虚拟——虚拟函数和虚拟继承。这本书让你知道:一旦你能够了解底层实现模型,你的程序代码将...

    深度探索 c++ 对象模型(pdf版)

    Inside The C++ Object Model专注于C++对象导向程序设计的底层机制,包括结构式语意、暂时性对象的生成、封装、继承,以及虚拟——虚拟函数和虚拟继承。这本书让你知道:一旦你能够了解底层实现模型,你的程序代码将...

    深度探索C.对象模型

    《Inside The C++ Object Model》专注于C++对象导向程序设计的底层机制,包括结构式语意、暂时性对象的生成、封装、继承,以及虚拟——虚拟函数和虚拟继承。这本书让你知道:一旦你能够了解底层实现模型,你的程序...

    C++课程管理信息系统,界面美观功能丰富,多级菜单列表,可视化界面

    4.打包方式: 将VS切换到Release分支,在项目Release设置内,代码生成选择MT,即可脱离C++和easyx环境运行,如果在过程中加载了资源,请在打包后的目录里相对exe文件进行补充,框架不支持VS的Resources 功能 1.现成的...

    数据结构、算法与应用:C++语言描述(原书第2版)第二部分

    5.5 在一个数组中实现的多重表 5.6 性能测量 5.7 参考及推荐读物 第6章 线性表——链式描述 6.1 单向链表 6.1.1 描述 6.1.2 结构chainNode 6.1.3 类chain 6.1.4 抽象数据类型linearList的扩充 6.1.5 类extendedChain...

    C++设计模式之享元模式(Flyweight)

    要创建具体的享元对象,我们需要创建一个享元工厂来统一管理对象的生成和输出,享元工厂是实现享元模式的关键。 举个例子,享元模式可以看成是一个工具箱,而享元对象就是工具箱内的具体的工具,我们在使用工具的...

    超级有影响力霸气的Java面试题大全文档

    面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。 4. 多态性:  多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化...

    教师信息管理系统课程设计new.doc

    而Visual Basic则是应用面向对象的程序设计方法,把程序和数据封装起来作为一个对象,并为每 一个对象赋予应有的属性,使对象成为实在的东西。在设计对象时,不必建立和描述每 个对象的程序代码,而是用工具画在界面...

    java 面试题 总结

    面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。 4. 多态性: 多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多...

    day020-继承加强和设计模式代码和笔记.rar

    先在类中创建一个对象 (联想到封装) =&gt; 提供一个公共的 getInstance给外部返回一个对象 3. 步骤: 1. 私有化构造方法 2. 在类中创建一个对象,并且用private、static、final修饰 ...

    Visual Assist

    当然和以前的版本一样,它可以同时支持C++、C#、VB等各种VS支持的语言,这样,一个基于不同开发语言的项目中也能方便地使用Visual Assist来帮忙我们开发,而且从VC6开始,中间还有VS 2002、VS2003、VS2005,一直到...

Global site tag (gtag.js) - Google Analytics