C++类几种情况的内存布局

来源:互联网 发布:网络信息抓取 编辑:程序博客网 时间:2024/06/09 18:50

对于C++开发者来说,了解其内存是非常必要的,同时C++的多态(动态绑定)的原理也是很重要的。

C++内存布局:

需要了解的几种情况:

1、无虚函数,非继承;

class simple {public:void simple_fun1() {};void simple_fun2() {};private:int simple_a_;};

内存布局:


没有虚函数,没有继承,所以只有成员变量需要分配空间。

2、有虚函数,非继承;

class Base {public:virtual void func1() { std::cout << "Func1()" << std::endl; }virtual void func2() { std::cout << "Func2()" << std::endl; }virtual void func3() { std::cout << "Func3()" << std::endl; }private:int a_;};
内存布局以及虚函数列表:


没有继承,有虚函数,所以有了虚函数列表vfptr,指向该类的虚函数列表,虚函数列表中记录当前类的虚函数;

3、无虚函数,继承;

class simple1 : public simple {public:void simple1_func1() {};private:int simple1_a_;};

内存布局:

普通的继承关系,而且基类中没有虚函数,所以不会生成虚函数列表,指向基类的和指向自身类的指针是同一个。

4、有虚函数,单继承;

class Derived : public Base {public:virtual void func2() { std::cout << "derived Func2()" << std::endl; }virtual void func4() { std::cout << "Func4()" << std::endl; }private:int b_;};
内存布局以及虚函数和列表:


单继承中,基类有虚函数,所以首先是虚函数列表,然后是从基类继承过来的成员变量,最后才是自己的成员变量。

由于override了基类的func2(),所以在虚函数列表中可以开看到,func2的域是Derived,而不再是基类Base。

5、有虚函数,多继承(非虚拟继承);

class Derived2 : public Base {public:virtual void func1() { std::cout << "derived2 Func1()" << std::endl; }virtual void func5() { std::cout << "Func5()" << std::endl; }private:int c_;};class Derived3 : public Derived, public Derived2 {public:void func6() { std::cout << "Func6()" << std::endl; }private:int d_;};

内存布局:

从以上内存布局可以发现一些问题,就是属于Base的成员变量a_出现了两次,虽然生成的时候可以通过,但是在实际使用过程中容易造成二义性出错,所以这种用法是需要尽量避免的。

虚函数列表:


虚函数列表中也有同样的问题,两个虚函数列表,有重复的函数Base::func3(),在实际中也要尽量避免。

6、无虚函数,多继承,虚拟继承;

将以上的Derived类和Derived2类对Base的继承改为虚拟继承:

class Derived3 : public Derived, public Derived2 {public:void func6() { std::cout << "Func6()" << std::endl; }private:int d_;};

内存布局:

最后一种情况使用了虚拟继承,内存布局就不同了,可以看出,一共有5个虚函数列表,在第一部分中(0~8),由两个虚函数列表和Derived的成员变量b_,第一个虚函数列表是Derived3类继承Derived类时生成的,第二个虚函数是Derived继承时Base生成的。

对于第二部分(12~20)同理,第三部分(24)则是Derived3自己的成员变量;

第四部分(28~32),则是Derived3间接继承Base生成的。

虚函数列表:

虚函数列表有点复杂,此处有点不明白,为什么会有负数出现,隐约能够看懂虚函数列表的指向。


从以上可以看到,在实例化一个类对象的时候,仅仅为类的成员变量和虚函数列表指针分配空间(虚函数的情况下),而成员函数属于整个类共有的,不会再对象中分配空间。因此,当虚函数更多的时候,占用的内存空间会更多,所以在实际项目中,关于类的继承体系的设计,需要考虑到这个方面。

如有问题,还请指正。

原创粉丝点击