c++中实例化对象的大小(转)

今天随手写了一个类,用sizeof()测试实例化类对象的大小时遇到了一些问题。

一般来说,对象大小由数据成员大小决定,不包含成员函数的大小。

在网上找了一篇很详细的例子,我遇到的问题为实例三情形,涉及到编译器的优化。

之所以写这篇《C++类的实例化对象的大小之sizeof()》,是因为在参加笔试的时候遇到如下这么一道题,当时感觉就是这个一个坑,但,我还是义无反顾的跳了下去,因为存在知识点盲区啊。现,总结一下,你不知道的C++类的实例化对象的大小之sizeof()。

class D
{
public:
 D()
 {

}

virtual ~D()
 {

}

private:
 int a ;
 char *p;
};

实例一:

class A
{
};

A a;
cout << sizeof(a) << endl;

运行结果:1

解释:空类,没有任何成员变量或函数,即没有任何存储内容;但是由A a可知,空类仍然可以实例化。一个类能够实例化,编译器就需给它分配内存空间,来指示类实例的地址。这里编译器默认分配了一个字节,以便标记可能初始化的类实例,同时使空类占用的空间最少(即1字节)。

实例二:

class B
{
private:
 int a;
};
B b;
cout << sizeof(b) << endl;

运行结果:4

解释:当类中有其它成员占据空间时,那一个字节就不算在内了,如本题:结果是4,而不是1+4=5。

实例三:

class BB
{
private:
 int a ;
 char b;
};
BB bb;
cout << sizeof(bb) << endl;

运行结果:8

解释:什么?怎么会是8?不应该是4 + 1 = 5吗?这里考察了对齐,涉及到编译器的优化。对于大多数CPU来说,CPU字长的整数倍操作起来更快,因此对于这些成员加起来不够这个整数倍,有可能编译器会插入多余的内容凑足这个整数倍;此外,有时候相邻的成员之间也有可能因为这个目的被插入空白,这个叫做“补齐”(padding)。所以,C++标准紧紧规定成员的排列按照类定义的顺序,但是不要求在存储器中是紧密排列的。因此,如上的一个字节的char在存储时被补全了,成为了4个字节。

实例四:

class C
{
private:
 int a ;
 char *p;
};
C c;
cout << sizeof(c) << endl;

运行结果:8

解释:一般情况下,如果是指针,则无论指针指向的是什么数据类型,都占4个字节的存储空间。

实例五:

class D
{
public:
 D()
 {

}

virtual ~D()
 {

}

private:
 int a ;
 char *p;
};
D d;
cout << sizeof(d) << endl;

运行结果:12

解释:考察虚函数。当类含有虚函数时,(不论是自己的虚函数,还是继承来的),那么类中就有一个成员变量信息:虚函数指针(4个字节),这个指针指向一个虚函数表,虚函数表的第一项是类的typeinfo信息,之后的项为此类的所有虚函数的地址。

更进一步的解释:当类中有虚函数的时候,编译器会为类插入一个我们看不及爱你的数据并建立一个表。这个表就是虚函数表,那个我们看不见的数据就是指向虚函数表的指针——虚表指针。虚函数表就是为了保存类中的虚函数的地址。我们可以把虚函数表理解成一个数组,数组中的每个元素存放的就是类中虚函数的地址。当调用虚函数的时候,程序不是像普通函数那样直接跳到函数的代码处,而是先取出虚表指针即得到虚函数表的地址,根据这个来到虚函数表里,从这个表理取出该函数的指针,最后调用该函数。

实例六:

class E
{
public:
 E()
 {

}

virtual ~E()
 {

}

private:
 int a ;
 char *p;
 static int b;
};
E e;
cout << sizeof(e) << endl;

运行结果:12

解释:考察静态成员变量的内存分配。由于静态成员变量是在静态存储区分配空间的,它不属于实例的一部分,因此类中的static成员变量不占据空间。

实例七:

class F:public E
{
public:
 F()
 {

}

~F()
 {

}

private:
 int c;
};
E e;
cout << sizeof(e) << endl;

运行结果:16

解释:派生类对象的存储空间 = 基类存储空间 + 派生类特有的非static数据成员的空间

实例八:

class G: public virtual E
{
public:
 G()
 {

}

~G()
 {

}

private:
 int c;
};
G g;
cout << sizeof(g) << endl;

运行结果:20

解释:如果是虚继承的话,类对象的存储空间大小 = 基类的存储空间 + 派生类特有的非static数据成员的存储空间 + 每一个类的虚函数存储空间(这个是额外加的,即按照这个公式,sizeof(g) = 12(E基类的存储空间) + 4(G特有的非static数据成员的存储空间) + 4(E类的虚函数的存储空间,如果E类中有多个虚函数,只算一次))。

实例九:

class H: public virtual E
{
public:
 H()
 {

}

~H()
 {

}

virtual void GetValue()
 {

}

private:
 int c;
};
H h;
cout << sizeof(h) << endl;

运行结果:24

解释:对比实例八,按照上面的解释:类对象的存储空间大小 = 基类的存储空间 + 派生类特有的非static数据成员的存储空间 + 每一个类的虚函数存储空间(sizeof(h) = 12(E基类的存储空间) + 4(G特有的非static数据成员的存储空间) + 4(E类的虚函数的存储空间,如果E类中有多个虚函数,只算一次)+ 4(H类的虚函数的存储空间,如果H类中有多个虚函数,只算一次))。

如上,就是我对于这种类型的总结,这种问题只能出现一次!!!

C++ 设计新思维》 下载见 http://www.linuxidc.com/Linux/2014-07/104850.htm

C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码 http://www.linuxidc.com/Linux/2014-05/101227.htm

读C++ Primer 之构造函数陷阱 http://www.linuxidc.com/Linux/2011-08/40176.htm

读C++ Primer 之智能指针 http://www.linuxidc.com/Linux/2011-08/40177.htm

读C++ Primer 之句柄类 http://www.linuxidc.com/Linux/2011-08/40175.htm

将C语言梳理一下,分布在以下10个章节中:

    1. Linux-C成长之路(一):Linux下C编程概要 http://www.linuxidc.com/Linux/2014-05/101242.htm
    2. Linux-C成长之路(二):基本数据类型 http://www.linuxidc.com/Linux/2014-05/101242p2.htm
    3. Linux-C成长之路(三):基本IO函数操作 http://www.linuxidc.com/Linux/2014-05/101242p3.htm
    4. Linux-C成长之路(四):运算符 http://www.linuxidc.com/Linux/2014-05/101242p4.htm
    5. Linux-C成长之路(五):控制流 http://www.linuxidc.com/Linux/2014-05/101242p5.htm
    6. Linux-C成长之路(六):函数要义 http://www.linuxidc.com/Linux/2014-05/101242p6.htm
    7. Linux-C成长之路(七):数组与指针 http://www.linuxidc.com/Linux/2014-05/101242p7.htm
    8. Linux-C成长之路(八):存储类,动态内存 http://www.linuxidc.com/Linux/2014-05/101242p8.htm
    9. Linux-C成长之路(九):复合数据类型 http://www.linuxidc.com/Linux/2014-05/101242p9.htm
    10. Linux-C成长之路(十):其他高级议题本文永久更新链接地址http://www.linuxidc.com/Linux/2015-02/112882.htm
时间: 2024-10-12 07:46:03

c++中实例化对象的大小(转)的相关文章

C++类的实例化对象的大小之sizeof()

之所以写这篇<C++类的实例化对象的大小之sizeof()>,是因为在参加笔试的时候遇到如下这么一道题,当时感觉就是这个一个坑,但,我还是义无反顾的跳了下去,因为存在知识点盲区啊.现,总结一下,你不知道的C++类的实例化对象的大小之sizeof(). class D { public: D() { } virtual ~D() { } private: int a ; char *p; }; 实例一: class A { }; A a; cout << sizeof(a) <

[转]ThinkPHP中实例化对象M()和D()的区别,select和find的区别

1.ThinkPHP中实例化对象M()和D()的区别 在实例化的过程中,经常使用D方法和M方法,这两个方法的区别在于M方法实例化模型无需用户为每个数据表定义模型类,如果D方法没有找到定义的模型类,则会自动调用M方法.通俗一点说:M实例化参数是数据库的表名.D实例化的是你自己在Model文件夹下面建立的模型文件 例如:$user = new UserModel(); 等价于$user = D('user'); 如果实例化的是一个空模型 例如 $Demo = new Model(); 那么它等价于

ThinkPHP中实例化对象M()和D()的区别,select和find的区别

原文:ThinkPHP中实例化对象M()和D()的区别,select和find的区别 1.ThinkPHP中实例化对象M()和D()的区别 在实例化的过程中,经常使用D方法和M方法,这两个方法的区别在于M方法实例化模型无需用户为每个数据表定义模型类,如果D方法没有找到定义的模型类,则会自动调用M方法.通俗一点说:M实例化参数是数据库的表名.D实例化的是你自己在Model文件夹下面建立的模型文件 例如:$user = new UserModel(); 等价于$user = D('user'); 如

Java中计算对象的大小

一.计算对象大小的方法 Java中如何计算对象的大小呢,找到了4种方法: 1.java.lang.instrument.Instrumentation的getObjectSize方法: 2.BTraceUtils的sizeof方法: 3.http://yueyemaitian.iteye.com/blog/2033046中提供的代码计算: 4.https://github.com/mingbozhang/memory-measurer提供的工具包: 本质上java.lang.instrument

ThinkPHP中实例化对象M()和D()的区别,select和find的区别 【转】

1.ThinkPHP中实例化对象M()和D()的区别 在实例化的过程中,经常使用D方法和M方法,这两个方法的区别在于M方法实例化模型无需用户为每个数据表定义模型类,如果D方法没有找到定义的模型类,则会自动调用M方法.通俗一点说:M实例化参数是数据库的表名.D实例化的是你自己在Model文件夹下面建立的模型文件 例如:$user = new UserModel(); 等价于$user = D('user'); 如果实例化的是一个空模型 例如 $Demo = new Model(); 那么它等价于

ThinkPHP中实例化对象M()和D()的区别

ThinkPHP中实例化对象M()和D()的区别?ThinkPHP如何实例化对象? 在实例化的过程中,经常使用D方法和M方法,这两个方法的区别在于M方法实例化模型无需用户为每个数据表定义模型类,如果D方法没有找到定义的模型类,则会自动调用M方法. 通俗一点说: M实例化参数是数据库的表名. D实例化的是你自己在Model文件夹下面建立的模型文件 例如:$user = new UserModel(); 等价于$user = D('user'); 如果实例化的是一个空模型 例如 $Demo = ne

ThinkPHP中实例化对象M()和D()的区别?ThinkPHP如何实例化对象?

在实例化的过程中,经常使用D方法和M方法,这两个方法的区别在于M方法实例化模型无需用户为每个数据表定义模型类,如果D方法没有找到定义的模型类,则会自动调用M方法.通俗一点说:M实例化参数是数据库的表名.D实例化的是你自己在Model文件夹下面建立的模型文件 例如:$user = new UserModel(); 等价于$user = D('user'); 如果实例化的是一个空模型 例如 $Demo = new Model(); 那么它等价于 $Demo = M(); --------------

magento 上传csv表格中实例化对象例子

app\code\core\Mage\Dataflow\Model\Convert\Parser\csv.php 文件是后台上传csv,插入到dataflow_batch_import中转表的代码,有如下代码片段 1.$batchModel = $this->getBatchModel(); 2.$batchModel->setParams($this->getVars()) ->setAdapter($adapterName) ->save(); 从上往下看, 第一行$th

如何准确计算Java对象的大小

     有时,我们需要知道Java对象到底占用多少内存,有人通过连续调用两次System.gc()比较两次gc前后内存的使用量在计算java对象的大小,也有人根据Java虚拟机规范中的Java对象内存排列估算对象的大小,这两种方法或多或少都有问题,因为System.gc()并不一定促发GC,同一个类型的对象在32位与64位JVM中使用的内存会不一样,在64位虚拟机中是否开启指针压缩也会影响Java对象在内存中的大小. 那么有没有一种既准确又方便的方法计算对象的大小呢?答案是肯定的.在Java