为什么类大小只取决于数据成员而不取决于成员函数
Why class size depend only on data members and not on member functions?
我想知道关于类大小的详细描述。我想知道是否只有数据成员&没有任何虚拟关键字的成员函数,那么为什么类大小只取决于数据成员。例如:
class A {
int a;
public:
int display() {
cout << "A=" << a << endl;
}
};
当我检查sizeof(A)
时,我发现它是4字节。为什么会这样?为什么成员函数对A类的大小没有影响?
感谢
因为类的函数没有保存在对象本身内部。从C编程的角度来看,A类的每个函数都有一个秘密参数,即this指针,所以实际上它们只是带有一个额外参数的函数。
例如,想象一下:
int display(A* thisptr)
{
//do something
printf("%d",thisptr->a);
return;
}
因此,显示函数被保存为一个带有一个额外参数的简单函数。不过,根据编译器的不同,名称会被篡改。
我相信不同的规则适用于涉及函数指针的虚拟函数,但由于我不确定其他人是否能在这件事上启发我们。
这取决于实现-标准中没有指定。然而,你是对的,非虚拟成员函数(甚至是第一个之后的虚拟函数)不会影响类大小。
这是因为如果类的每个实例都有指向所有函数的指针,那么它将占用大量内存。他们为什么会这样做?在运行时,对象知道它是什么类型,并且可以调用适当的函数。同一个函数在不同的实例中是相同的,不同的是它所操作的对象,它作为一个参数在后台传递。
函数/方法存储为代码,而不是数据。就像一个可执行文件存储为单个文件一样,可以多次启动,并且它的多个实例将具有不同的数据。类似地,函数是和可执行代码,并且您传递给它的数据可能不同(对于相同的文字处理软件,类似于不同的文档)。
可执行代码不会有任何sizeof
,因为当程序运行时,它们不会占用堆栈或堆上的空间。它本身存储在可执行映像中,并在启动程序时由操作系统加载一次。
就像普通的C函数一样,C++方法只是内存中的一个地址,供调用时执行跳转到该地址。唯一的区别是第一个参数,它是指向调用函数的对象的指针。
除了为实现虚拟函数和虚拟继承而引入的隐藏数据成员外,实例大小完全由类的数据成员和基类决定来自C++:Under the Hood(1994)如果你想了解更多。
成员函数是流程文本段的一部分,对象是流程数据段的一部份。因此,由于对象只是数据,它通过添加类中所有数据成员的大小来计算大小。成员函数对所有对象都是通用的,它的区别仅在于特定对象指针(称为该指针)的第一个参数,该指针作为隐藏指针传递给类的每个成员函数。
因为函数状态留在堆栈中,并在函数进入/退出时创建/删除。
在对象的大小中,只有有助于存储对象状态的成员。函数只是一段从给定点开始的代码,它不依赖于它所引用的特定对象实例
思考
A a1, a2;
a1.a和a2.a是不同的,但是a1.display()和a2.dispay()是相同的函数代码(将int A::display()
)视为int display(A* this)
)
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 助记符和指向成员语法的指针
- 用于访问容器<T>数据成员的正确 API
- 内置函数可查看CPP中的成员变量
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 内存中类位置的成员是否取决于类成员在类定义中的位置?
- 为什么c++中类的大小取决于数据成员的公共/私有状态
- 初始化数据成员取决于构造函数中的条件
- 基类数据成员类型取决于派生类
- 如何在基本模板类中声明成员,其中类型取决于派生类的类型
- 一次启用 MANY 类的成员字段,具体取决于模板<T>
- 为什么类大小只取决于数据成员而不取决于成员函数
- 成员函数模板的参数数量取决于一个积分模板参数
- 声明成员与否取决于模板形参
- 为什么类的大小取决于成员声明的顺序?以及如何
- 成员函数的实现取决于模板参数