类在内存中的存储问题?

JYYCOM 2008-10-15 04:28:24
一个没有变量也没有虚方法的类在内存中占1个字节,有虚方法的话,指向虚表的指针占4个字节,变量根据情况开辟内存。
那么普通方法为什么在类中没有占空间,这些信息保存在什么位置,指向实例的指针是如何通过'->',调用到类的方法的。
自己对多态有些理解了,可是像下面这种情况,pb也是指向派生类的指针,只是因为他是由基类声明的,他是如何找到基类方法的。

谢谢大家!
Derived d;
Base *pb = &d;
Derived *pd = &d;
pb->g(3.14f); //运行结果: Base::g(float) 3.14
pd->g(3.14f); //运行结果: Derived::g(int) 3
...全文
298 10 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
JYYCOM 2008-10-16
  • 打赏
  • 举报
回复
多谢楼上几位的指点!
PJQ_blues 2008-10-16
  • 打赏
  • 举报
回复
类对象的非虚方法是静态绑定的,类似于库函数,对象直接决定调用那一个,
JYYCOM 2008-10-15
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 study_live 的回复:]
g跟h是非虚方法, 继承类与父类指向同一地址
f是虚方法, c++中类继承中,每个对像都维护一个虚似表, 用来指示指向函数的实际地址.

Derived d; //假设d中f地址是0x8321
Base *pb = &d; //虚表中f指向的实际地址也原始类对象中的地址0x8321
Derived *pd = &d;//类似

所以输出都是Derived::f(float) 3.14
[/Quote]
多谢赐教!
"但是可以说的一条原则是,非虚函数的调用是根据指针类型,虚函数的调用是根据对象类型"
"g跟h是非虚方法, 继承类与父类指向同一地址"
还是理解不了指针是如何找到类的非虚方法,在类对象的内存中似乎没有非虚方法的信息,这些信息存放在什么地方?
study_live 2008-10-15
  • 打赏
  • 举报
回复
C++虚函数表与对象布局
[转载]2006-10-26 23:33每个含有虚函数的类有一张虚函数表(vtbl),表中每一项指向一个虚函数的地址,实现上是一个函数指针的数组。

虚函数表既有继承性又有多态性。每个派生类的vtbl继承了它各个基类的vtbl,如果基类vtbl中包含某一项,则其派生类的vtbl中也将包含同样的一项,但是两项的值可能不同。如果派生类重载(override)了该项对应的虚函数,则派生类vtbl的该项指向重载后的虚函数,没有重载的话,则沿用基类的值。

在类对象的内存布局中,首先是该类的vtbl指针,然后才是对象数据。在通过对象指针调用一个虚函数时,编译器生成的代码将先获取对象类的vtbl指针,然后调用vtbl中对应的项。对于通过对象指针调用的情况,在编译期间无法确定指针指向的是基类对象还是派生类对象,或者是哪个派生类的对象。但是在运行期间执行到调用语句时,这一点已经确定,编译后的调用代码能够根据具体对象获取正确的vtbl,调用正确的虚函数,从而实现多态性。分析一下这里的思想所在,问题的实质是这样,对于发出虚函数调用的这个对象指针,在编译期间缺乏更多的信息,而在运行期间具备足够的信息,但那时已不再进行绑定了,怎么在二者之间作一个过渡呢?把绑定所需的信息用一种通用的数据结构记录下来,该数据结构可以同对象指针相联系,在编译时只需要使用这个数据结构进行抽象的绑定,而在运行期间将会得到真正的绑定。这个数据结构就是vtbl。可以看到,实现用户所需的抽象和多态需要进行后绑定,而编译器又是通过抽象和多态而实现后绑定的。

下面说一下多重继承。多重继承的两个基类如果继承了同一个类,则其派生类相当于继承了该类两次,vtbl也继承了两次。对象布局中,该类的数据有两份,vtbl指针有两个,分别指向两次被继承的vtbl。但派生类重载该类的虚函数时只能重载一次,那么重载后的函数地址将占据vtbl的哪个位置?通过写程序测试,我觉得应该是同时出现在所继承的两个vtbl的相应位置,有待进一步验证。

说到虚函数机制,对象指针的类型转换也是要弄清的,这里就不说了。还有一个this指针的问题,提一下。虚函数调用的时候也是需要传递this指针的,这没什么奇怪,但是这时的this指针就隐含着一个问题,它要和实际调用的虚函数相一致,即this指针也要实现多态性。在多重继承的情况下,这个问题不是那么简单的,请参考[《C++语言的设计和演化》p203]。

------------

study_live 2008-10-15
  • 打赏
  • 举报
回复
g跟h是非虚方法, 继承类与父类指向同一地址
f是虚方法, c++中类继承中,每个对像都维护一个虚似表, 用来指示指向函数的实际地址.

Derived d; //假设d中f地址是0x8321
Base *pb = &d; //虚表中f指向的实际地址也原始类对象中的地址0x8321
Derived *pd = &d;//类似

所以输出都是Derived::f(float) 3.14

JYYCOM 2008-10-15
  • 打赏
  • 举报
回复
类的代码比较简单,如下
// BaseDerive.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream.h>
#include <string>

class Base

{

public:

virtual void f(float x){ cout << "Base::f(float) " << x << endl; }

void g(float x){ cout << "Base::g(float) " << x << endl; }

void h(float x){ cout << "Base::h(float) " << x << endl; }
};

class Derived : public Base

{

public:

virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }

void g(int x){ cout << "Derived::g(int) " << x << endl; }

void h(float x){ cout << "Derived::h(float) " << x << endl; }

};

void main(void)

{

Derived d;
cout<<sizeof(Base)<<endl;
cout<<sizeof(Derived)<<endl;

Base *pb = &d;

Derived *pd = &d;

//

// pb->f(3.14f); //运行结果: Derived::f(float) 3.14

pd->f(3.14f); //运行结果: Derived::f(float) 3.14


pd->f('3);

// Bad : behavior depends on type of the pointer

pb->g(3.14f); //运行结果: Base::g(float) 3.14

pd->g(3.14f); //运行结果: Derived::g(int) 3

// Bad : behavior depends on type of the pointer

pb->h(3.14f); //运行结果: Base::h(float) 3.14

pd->h(3.14f); //运行结果: Derived::h(float) 3.14

}
dulinbo 2008-10-15
  • 打赏
  • 举报
回复
一个没有变量也没有虚方法的类在内存中占1个字节,有虚方法的话,指向虚表的指针占4个字节,变量根据情况开辟内存。
-----有虚方法的话,类中就有一个vptr的变量指向虚函数表

那么普通方法为什么在类中没有占空间,这些信息保存在什么位置,指向实例的指针是如何通过'->',调用到类的方法的。
----方法为所有实例公用,没必要一个实例一份吧,成员变量的值可以是每个类的实例一个值,所以类的实例在内存中只有成员变量,如何调用方法具体的机制不清楚。

自己对多态有些理解了,可是像下面这种情况,pb也是指向派生类的指针,只是因为他是由基类声明的,他是如何找到基类方法的。

谢谢大家!
Derived d;
Base *pb = &d;
Derived *pd =…
----贴出你类的代码。但是可以说的一条原则是,非虚函数的调用是根据指针类型,虚函数的调用是根据对象类型,因为这时里面有个VPTR,指向了虚函数表。你可以调试一下,拖到watch窗口看一下对象,在调试下可以看到这个vptr。
taodm 2008-10-15
  • 打赏
  • 举报
回复
去看《深度探索C++对象模型》
boys2002 2008-10-15
  • 打赏
  • 举报
回复
顶下先



等 高手 回答


先关注一下




呵呵!!!


但是想拿分
xkyx_cn 2008-10-15
  • 打赏
  • 举报
回复
贴出你的代码

另外 overload与override是不同的

65,184

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧