C++对象的内存布局

4

据我所知,当类定义时,所有成员函数将在单独的内存中创建,并且对于所有对象都是通用的。只有成员变量会为每个对象分别创建。但是,当使用对象调用成员函数时,该成员函数如何执行?

这些成员函数的地址存储在哪里?


class B{
    public:
    int a;
    void fun(){

    }
};

int main(){
    B b;
    std::cout<<sizeof(b)<<std::endl;
}

如果我执行这个程序,我会得到输出4(只是成员变量)。但是调用b.fun()会正确地调用它的成员函数。它是怎么在没有将地址存储在对象内部的情况下调用的?成员函数地址存储在哪里?

是否有类内存布局这样的东西,其中这些地址将被存储?


2
你今天的谷歌搜索关键词是“C++符号重整”。 - Sam Varshavchik
@SamVarshavchik 我认为混淆不会给出最直接的答案。 - SergeyA
假设您创建了一个非成员函数 void fun(B *b) {},并执行 fun(b);。现在,您不会感到惊讶,因为不相关的函数不会影响 B 的大小?成员函数的工作方式类似,只是调用它们的语法不同。 - HolyBlackCat
1
具体实现细节因不同情况而异,但通常非虚拟成员函数的调用方式与其他函数相同(带有一个隐藏的 this 参数)。通常要调用的函数地址会被“存储”在调用指令本身中,作为立即操作数。不需要在其他地方为函数指针留出空间;特别是它不会存储在该类型对象的内存布局中。如果您想了解内部细节,请指定您的编译器/架构/操作系统/ABI/代码模型等信息。 - Nate Eldredge
2个回答

8

非虚拟成员函数和普通的非成员函数非常相似,唯一的区别在于在调用时传递一个指向类实例的指针作为第一个参数。

这由编译器自动完成,因此(以伪代码表示),你的调用b.fun()可以被编译成

B::Fun(&b);

B::Fun可以看作是一个普通函数。该函数的地址不需要存储在实际对象中(该类的所有对象将使用相同的函数),因此类的大小不包括它。


不相关的侧面说明:C++标准没有很好地定义this如何进入方法。上述描述是最直接的方法,也是我在实践中看到的唯一方法。但是,this可以是一个隐藏的最后一个参数,或者通过精灵魔法传输到方法中。问题是,只要出现this在方法中,你并不真正关心它是如何出现的。 - user4581301

4
这些地址会存储在类内存布局中吗?
对于使用virtual声明的函数,是的。这种情况下,所述函数的地址将存储在表中,并在运行时查找。这进而允许您的代码在调用函数时根据对象的类型分派到正确的函数。
非虚函数不是这样工作的。它们以与自由(即非成员)函数相同的方式存储,函数名称前缀为类名。不需要在对象本身中占用存储空间。
在两种情况下,一个隐藏的this指针被传递给被调用的函数。这就是将其“连接”到您的对象的方式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接