类、对象的内存模型

原问题如下:

#include <iostream>
using namespace std;
class base{
public:
 virtual void fun1()
 {
 cout << "fun1 called !" << endl;
 }
 void fun2()
 {
 cout << "fun2 called !" << endl;
 }
};
int main()
{
    base s;
    cout << sizeof(s) << endl;
    return 0;
}
代码的结果为4。
这个我觉得是因为那个虚函数表里的一个指针占了4个字节
但是如果我去掉virtual 代码的结果为1

类中的普通成员函数占对象的空间吗?数据成员所占空间的计算是否也是和结构体类似呢?
这个就不明白了,请各位指点。。

我的回答如下:

这个涉及到类和结构体,在C++内部的排列方式。
我也不是很了解,只能就自己了解的一点知识做点回答,欢迎大家指正。
我们知道,C和C++虽然都支持结构体,但是,实际上表现是不一样的。C++的结构体,可以认为是类的一种变体,二者的差异性,类中成员,如果不声明,默认是Private的,结构体中成员,如果不声明,则默认是Public的。
但是,在C++里面,二者内部都可以内置成员函数,而C的结构体,内部只允许存在成员变量,如果需要内置成员函数,需要程序员显式声明函数指针变量,换句话说,就是C在结构体中管理成员函数,是程序员自己来管理,C++则是编译器代为管理。
这意味着什么呢?
在C++中,成员函数和成员变量,都是类和结构体的成员,但二者有所差异。
编译器在编译每个类时,不管这个类以后会实例化几个对象,首先,它会提取这些类的共性,放到一起,做成一个表。
比如类里面的非虚函数,这类函数,所有的对象共享一段函数代码,自然没有必要每个对象内部都设置一个函数指针,这太浪费内存了。
因此,一个类,所有的非虚函数,会被编译器排成一个符号表,放置在特定的编译期基础变量区。这实际表现看,是放在exe文件里面的,在调用一个程序时,是直接从文件中读出,并经过地址修订,准备使用,这部分连基栈都算不上,算是常量区了,所有的常量也是放在这个区。
嗯,函数内部的静态变量,类中的静态变量,静态函数,都是这个区。
那,除掉这些,类里面还有什么呢?
还有虚函数,我们知道,虚函数表示可能继承,事实上,多次(不是多重)继承后,一个类的虚函数内部会有一个栈,每个虚函数都有一个栈,每次调用该函数,会从栈顶开始call,当然,如果程序员愿意,也可以在继承的虚函数内部,通过调用父类的同名虚函数,逐级向下call,直至call完所有的虚函数为止。
这就说明,虚函数和普通成员函数不同,每个对象都有可能变化,因此,编译器就不敢把这个函数的指针,放在常量区,必须跟着对象走,注意,不是类,类是没有实体的,因此,不存在sizeof,只有对象存在大小。
还有就是普通成员变量,这些内容,每个对象也是不一样的,因此,每个对象必须自己建立一个表来管理,否则大家就混了。
因此,我们知道了,每个类,实例化对象之后,其实对象的实体在内存中的存储,就只包含虚函数和普通成员变量,这是C++编译器为了节约内存做得优化。
我们回到你的代码看,你的代码中,fun2是普通函数,被编译器放到常量区去了,因此,不占用对象空间,虚函数fun1,则需要占用,我们知道,32位操作系统,一个指针是4Bytes,函数指针也是指针,因此,你的结果是4Bytes。
取消了virtual 之后,fun1也变成了普通函数,因此和fun2等同处理,就不再占用对象空间,因此,对象空间为0了。
不过,我隐隐约约听谁说过,C++语言不允许对象空间为0,这样的话,对象指针就没有落点了,因此,一个对象的空间,至少占用1Byte,这就是你的结果为1的原因。
不知道这样能不能帮你解惑,呵呵,一家之言哈,欢迎拍砖。

你可能感兴趣的:(类、对象的内存模型)