前面我们提到过C中的struct结构体的大小,什么内存对齐,偏移量,然后Linux和Window下的还不一样,
搞懂了上面的这些,那就明白了C++中的了吗??
这里的结构体可是还有函数的,还有虚函数,友员函数,继承,多重继承,虚继承,等等一大堆东西,那这里面又是咋样的呢??
1,class空类
C++的空类是指这个类不带任何数据,即类中没有非静态数据成员变量,没有虚函数,也没有虚基类,也就是说:空类对象不使用任何空间,因为没有任何对象需要存储,但是,但是,但是,:C++标准规定,凡是一个对立的对象都必须具有非零大小:::::
所以,也就是说:空类或者空类的对象的大小也不为0。。。
#include <iostream> using namespace std; class test { }; int main() { cout<<sizeof(test)<<endl; return 0; }运行结果:
所以我们可以看到空类test的大小为1
其实在C++早起的编译器中,这个值为0(也就是说空类的大小),然而当我们创建这样的对象是,它与紧接着后面的对象有相同的地址:
test tt;
int a;(这里tt和变量a有相同的地址),这样的话我们对对象tt的操作就会直接影响a,所以对与如今的编译器来说,空类的大小为1、
类的实例化就是在内存中分配一块地址,每一个实例在内存中都是独一无二的地址。所以空类实例化后也就有了自己独一无二的地址了
2,当含有虚成员函数时:
#include <iostream> using namespace std; class A { public: virtual void fun(); }; int main() { cout<<sizeof(A)<<endl; return 0; }
此时,类的大小为4,因为在类中隐藏了一个指针,该指针指向虚函数表(具有虚函数表的地址),正是因为如此,使得C++能够支持多态,即在运行时绑定函数的地址。
运行结果(Linux):
所以可以看出,虚函数在linux系统里面占了8个字节
#include <iostream> using namespace std; class A { public: virtual void aa() { } private: char k[3]; }; class B:public A { public: virtual void bb() { } }; int main() { cout<<"A is size:"<<sizeof(A)<<endl; cout<<"B is size:"<<sizeof(B)<<endl; return 0; }
16,16
window中(vc,dev-c++)
8,8
说明:有虚函数的类有个virtual table(虚函数表),里面包含了类的所有虚函数,类中有个virtual table pointers,通常是:vptr指向这个virtual table,占有4个字节,成员类B public继承于A,类B的虚函数表里实际上有两个虚函数
A::aa()和B::bb()都在虚表里面,虚表的每一个表项保存着一个虚函数的入口地址。当调用虚函数时,我们是先找到虚表中的表项,找到入口地址再执行。
然而对于含有虚函数的类的大小而言,大小等于成员变量+指向虚表的指针
类B的大小等于char k【3】的大小加上一个指向虚函数表指针vptr的大小,并且还必须考虑内存对齐,故结果为:8
所以,觉得应该是在linux下:在类中涉及到虚函数的指针(指向虚表的指针+指向父类的指针)都应该占用8个字节,下面的程序都可以这样理解!!!
#include <iostream> using namespace std; class A { public: virtual void aa() { } private: char k[3]; }; class B:public A { }; int main() { cout<<"A is size:"<<sizeof(A)<<endl; cout<<"B is size:"<<sizeof(B)<<endl; return 0; }window下(vc和dev-c++):
A is size:8
B is size:8
linux下:
A is size:16
B is size:16
类B看上去没有虚函数,实际上类B也是有的,它是通过继承A来的,所以说,类A和类B的虚函数表里面都是A::aa()
#include <iostream> using namespace std; class A { public: virtual void aa() {} virtual void aa1() {} private: char k[3]; }; class B:public A { virtual void bb() {} virtual void bb1() {} }; int main() { cout<<"A is size:"<<sizeof(A)<<endl; cout<<"B is size:"<<sizeof(B)<<endl; return 0; }
A is size:8
B is size:8
linux下:
A is size:16
B is size:16
可以看出:一个类中若存在多个虚函数,无论有多少个虚函数都只是存在一个指向虚表的指针,虚表的每一个表项保存着一个虚函数的入口地址。当调用虚函数时,我们是先找到虚表中它对应的入口地址,找到入口地址再执行。对于上面这种情况:
类A的虚表中存在的是:A:aa() ,A:aa1()
类B的虚表中存在的是:A:aa() ,A:aa1(),B:bb(),B:bb1()
#include <iostream> using namespace std; class A { public: virtual void aa() {} virtual void aa1() {} private: char k[3]; }; class B { virtual void bb() {} virtual void bb1() {} }; class C:public A,public B { public: virtual void aa(){} //重写虚函数 virtual void cc() {} }; int main() { cout<<"A is size:"<<sizeof(A)<<endl; cout<<"B is size:"<<sizeof(B)<<endl; cout<<"C is size:"<<sizeof(C)<<endl; return 0; }
A is size:8
B is size:4
C is size:12
linux下:
A is size:16
B is size:8
C is size:24
类A和B的大小就不用解释了,参照上面我们所讲的,类C(有虚函数的覆盖)多重继承于A和B首先我们来看成员变量,有一个继承A的char[3].
在来看虚函数,那么类C中的虚函数是如何分布的,它可是继承了两个基类啊!!!(有两个虚函数表)
1,第一个虚函数表,继承于类A的虚函数和C自己的虚函数(C::aa(),A::aa2(),C::cc()),当然如果我们没有重写虚函数的话,那么第一个虚函数表就是:(A::aa(),A::aa2(),C::cc())
2,第二个虚函数表,继承于类B的虚函数和C自己的虚函数(B::bb(),B::bb2(),C::aa(),C::cc())嗯嗯,应该就是这样了
所以说:总的大小就是指向两张虚表的大小在加上继承过来的成员变量,加上内存对齐的因素就是12字节
#include <iostream> using namespace std; class A { public: virtual void aa() {} private: char k[3]; }; class B:virtual public A { }; int main() { cout<<"A is size:"<<sizeof(A)<<endl; cout<<"B is size:"<<sizeof(B)<<endl; return 0; }
window下(vc和linux)
B is size:12
linux下:
A is size:16
B is size:24
类B的虚函数表里有A::aa(),所以有一个指向虚表的指针,又因为是虚继承,所以还有一个指向父类的指针,加上成员变量,考虑内存对齐,所以总大小为12
友元函数:
#include <iostream> using namespace std; class A { public: friend void kk(); }; int main() { cout<<"A is size:"<<sizeof(A)<<endl; return 0; }
A is size :1
所以我们可以知道友元函数如同其他函数就是一样的,也是不影响类的大小,如上,类A也相当于空类!
#include <iostream> using namespace std; class A { public: static int a; }; int main() { cout<<"A is size:"<<sizeof(A)<<endl; return 0; }
A is size :1
所以此刻A类还是空类!!!
空类是指这个类不带任何数据,即类中没有非静态数据成员变量,没有虚函数,也没有虚基类,也没有函数(包括友元函数)
本文关于虚函数的类的介绍:
摘自(谢谢啦):http://www.cnblogs.com/luxiaoxun/archive/2012/09/01/2666395.html
关于C++虚函数,可以看《C++虚函数表解析》:http://blog.csdn.net/haoel/article/details/1948051