了解你所使用的编程语言究竟是如何实现的,对于C++程序员可能特别有意义。首先,它可以去除我们对于所使用语言的神秘感,使我们不至于对于编译器干的活感到完全不可思议;尤其重要的是,它使我们在Debug和使用语言高级特性的时候,有更多的把握。当需要提高代码效率的时候,这些知识也能够很好地帮助我们。
简单非多态的内存布局
class X { int x; float xx; public: X() {} ~X() {} void printInt() {} void printFloat() {}};
| | |------------------------| <------ X class object memory layout | int X::x | |------------------------| stack segment | float X::xx | | |------------------------| | | | \|/ | | | |------|------------------------|---------------- | X::X() | |------------------------| | | X::~X() | | |------------------------| \|/ | X::printInt() | text segment |------------------------| | X::printFloat() | |------------------------| | |
在本示例中
this指针是一个隐含于每一个成员函数中的特殊指针。它是一个指向正在被该成员函数操作的对象,也就是要操作该成员函数的对象。this作用域是在类内部,当对一个对象调用成员函数时,编译程序先将对象的地址赋给this指针,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。也就是说,即使你没有写this指针,编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含形参。被调用的成员函数函数体内所有对类成员的访问,都会被转化为“this->类成员”的方式。
针对第二点,我们类似于:
A x;x.printInt();
其中,X::printInt()这个行为,在编译器中,将处理为
printInt(const X* this)
那么,x.printInt()调用处理将最终成为
printInt(&x);
同时具有虚函数和静态数据成员的内存布局
class X { int x; float xx; static int count; public: X() {} virtual ~X() {} virtual void printAll() {} void printInt() {} void printFloat() {} static void printCount() {}};
其内存布局如下
| | |------------------------| <------ X class object memory layout | int X::x |stack |------------------------| | | float X::xx | | |------------------------| |-------|--------------------------| | | X::_vptr |------| | type_info X | \|/ |------------------------| |--------------------------| | o | | address of X::~X() | | o | |--------------------------| | o | | address of X::printAll() | | | |--------------------------| | |------|------------------------|------------ | static int X::count | /| |------------------------| | | o | data segment | o | | | | \|/------|------------------------|------------ | X::X() | |------------------------| | | X::~X() | | |------------------------| | | X::printAll() | \|/ |------------------------| text segment | X::printInt() | |------------------------| | X::printFloat() | |------------------------| | static X::printCount() | |------------------------| | |
class X { int x; string str; public: X() {} virtual ~X() {} virtual void printAll() {}}; class Y : public X { int y; public: Y() {} ~Y() {} void printAll() {}};
其内存布局信息如下
| | |------------------------------| <------ Y class object memory layout | int X::x |stack |------------------------------| | | int string::len | | |string X::str ----------------| | | char* string::str | \|/ |------------------------------| |-------|--------------------------| | X::_vptr |------| | type_info Y | |------------------------------| |--------------------------| | int Y::y | | address of Y::~Y() | |------------------------------| |--------------------------| | o | | address of Y::printAll() | | o | |--------------------------| | o | ------|------------------------------|-------- | X::X() | |------------------------------| | | X::~X() | | |------------------------------| | | X::printAll() | \|/ |------------------------------| text segment | Y::Y() | |------------------------------| | Y::~Y() | |------------------------------| | Y::printAll() | |------------------------------| | string::string() | |------------------------------| | string::~string() | |------------------------------| | string::length() | |------------------------------| | o | | o | | o | | |
class X {public: int x; virtual ~X() {} virtual void printX() {}}; class Y {public: int y; virtual ~Y() {} virtual void printY() {}}; class Z : public X, public Y {public: int z; ~Z() {} void printX() {} void printY() {} void printZ() {}};
内存布局如下
| | |------------------------------| <------ Z class object memory layoutstack | int X::x | | |------------------------------| |--------------------------| | | X:: _vptr |----------------->| type_info Z | | |------------------------------| |--------------------------| \|/ | int Y::y | | address of Z::~Z() | |------------------------------| |--------------------------| | Y:: _vptr |------| | address of Z::printX() | |------------------------------| | |--------------------------| | int Z::z | | |--------GUARD_AREA--------| |------------------------------| | |--------------------------| | o | |---------->| type_info Z | | o | |--------------------------| | o | | address of Z::~Z() | | | |--------------------------|------|------------------------------|--------- | address of Z::printY() | | X::~X() | | |--------------------------| |------------------------------| | | X::printX() | | |------------------------------| | | Y::~Y() | \|/ |------------------------------| text segment | Y::printY() | |------------------------------| | Z::~Z() | |------------------------------| | Z::printX() | |------------------------------| | Z::printY() | |------------------------------| | Z::printZ() | |------------------------------| | o | | o | | |
在多继承层次结构中,创建的虚拟表指针(vptr)的确切数目将为N-1,其中N代表类的数目。
如果尝试使用任何基类指针调用Z类的方法,则它将使用相应的虚拟表进行调用。如下例子所示:
Y *y_ptr = new Z;y_ptr->printY(); // OKy_ptr->printZ(); // Not OK, as virtual table of class Y doesn't have address of printZ() method
在上面的代码中,y_ptr将指向完整Z对象内类Y的子对象。
结果,调用任何方法,例如使用y_ptr-> printY()。 使用y_ptr的解析方式如下:
( *y_ptr->_vtbl[ 2 ] )( y_ptr )
虚继承内存布局
class X { int x; };class Y : public virtual X { int y; };class Z : public virtual X { int z; };class A : public Y, public Z { int a; };
其布局如下:
| | Y class ------> |----------------| <------ A class object memory layoutsub-object | Y::y | |----------------| |------------------| | Y::_vptr_Y |------| | offset of X | // offset(20) starts from Y Z class ------> |----------------| |----> |------------------| sub-object | Z::z | | ..... | |----------------| |------------------| | Z::_vptr_Z |------| |----------------| | A sub-object --> | A::a | | |------------------| |----------------| | | offset of X | // offset(12) starts from Z X class -------> | X::x | |----> |------------------| shared |----------------| | ..... | sub-object | | |------------------|
了解内存布局,对我们的项目开发会提供很大的便利,比如对coredump的调试
到此这篇关于c++对象内存布局的文章就介绍到这了,更多相关c++对象内存布局内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!
本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728