C++对象在内存中的存放方式

来源:互联网 发布:java soap 编辑:程序博客网 时间:2024/06/01 10:01

对象占有一定的内存,该内存上存放的是该对象的相关数据,按先后顺序如下:

1、虚表指针:如果该类有虚函数的话,将存放虚表指针,该指针指向该类的虚函数表,即指向表中的第一个元素。续表中存放的是该类虚函数的地址;

2、基类数据成员(如果有基类);

3、自己的数据成员;


对象在调用成员函数时的方式:

1、调用非虚成员函数:其实相当于是非成员函数调用,实现根据对象类型找到该对象所属类,并在类中查找被调用的成员函数,查找到后调用;

实际上,类的成员函数都有一个隐藏的参数,this指针,成员函数的调用在编译时就被替换为一个非成员函数的调用,不涉及对象的具体内容,只涉及对象的类型,是一种静态的绑定关系,即根据调用者所属类型确定调用哪个函数。如:

a.fun()—>fun(&a)

编译器根据a所属的类查找到要调用的函数,然后将成员函数的调用转变为一个非成员函数的调用;

2、调用虚函数:实现根据虚表找到该类拥有的虚函数地址,然后查找到被调用的虚函。由于需要用到虚表,而虚表是保存在每个对象中的,因此必须要根据对象中存储的虚表进行函数调用,这就无法在编译时实现,只能是运行时进行,因此一种动态绑定关系,即根据调用者内容确定调用哪个函数。


因此,当用一个基类指针指向一个派生类对象的时候:

Class Base

{

/*构造、析构函数省略*/

virtual void fun1()

{

cout<<"call Base::fun1";

}

void fun2()

{

cout<<"call Base::fun2";

}

Class Derived : public Base

{

/*构造、析构函数省略*/

virtual void fun1()

{

cout<<"call Derived::fun1";

}

void fun2()

{

cout<<"call Base::fun2";

}


}


Derived D;

Base* pBase = &D;


例一:pBase->fun1();

上面的函数调用调用的是Derived的fun,因为虽然指针是基类的指针,但是在查找虚表时用到的是对象的内存上的虚表地址,而该对象是派生类,虚表中的函数是派生类的虚函数; 

例二:pBase->fun2();

上面这个调用调用的是基类的fun2,因为非虚函数的调用只看调用者的类型,不涉及调用者实际在内存上的信息;



0 0