假设我们有一个看起来像这样的课程:
class A
{
public:
int FuncA( int x );
int FuncB( int y );
int a;
int b;
};
现在,我知道这个类的对象将只用两个ints
布局在内存中。也就是说,如果我创建了类A
的实例的向量,则一个实例将有两个ints
,然后对于第二个实例将有两个ints
等。对象是POD
但是让我们说这堂课看起来像这样:
class B
{
public:
int FuncA( int x );
int FuncB( int y );
};
这个类的对象在内存中看起来是什么样的?如果我用B
的实例填充向量...向量中有什么?我被告知非虚拟成员函数最终被编译为自由函数,这些函数与声明它们的类的实例完全无关(虚函数也是,但是对象存储带有函数指针的vtable) 。访问限制仅仅是语义上的“人”级别。只有类的数据成员(和vtable等)实际上构成了对象的内存结构。
再说一次,类B
的对象在内存中是什么样的?它是某种占位符价值吗?必须有东西,我可以拿对象的地址。它必须指向某事。无论是什么,编译器是否允许内联/优化这些对象并将方法调用视为正常的自由函数调用?如果我创建这些的向量并在每个对象上调用相同的方法,编译器是否可以消除向量并用一堆普通的调用替换它?
我只是好奇。
答案 0 :(得分:7)
C ++中的所有对象都保证sizeof> = 1,以便每个对象都有一个唯一的地址。
我没有尝试过,但我想在你的例子中,编译器会为数组/向量中的每个函数对象分配但不初始化1个字节。
答案 1 :(得分:6)
正如Ferruccio所说,C ++中的所有对象都保证大小至少为1.大多数情况下,它是1个字节,但填写了对齐的大小,但无论如何。
但是,当用作基类时,它不需要填充任何空格,因此:
class A {} a; // a is 1 byte.
class B {} b; // b is 1 byte.
class C { A a; B b;} c; // c is 2 bytes.
class D : public A, B { } d; // d is 1 byte.
class E : public A, B { char ee; } e; // e is only 1 byte
答案 2 :(得分:4)
这个类的对象在内存中看起来像什么?
这完全取决于编译器。空类的实例必须具有非零大小,以便不同的对象具有不同的地址(除非它被实例化为另一个类的基类,在这种情况下它根本不占用任何空间)。通常,它将由一个未初始化的字节组成。
无论是什么,编译器是否允许内联/优化这些对象并将方法调用视为正常的自由函数调用?
是;编译器不必创建对象,除非您执行类似于获取其地址的操作。标准库中使用了很多空函数对象,因此重要的是它们不会引入任何不必要的开销。
答案 3 :(得分:2)
我进行了以下实验:
#include <iostream>
class B
{
public:
int FuncA( int x );
int FuncB( int y );
};
int main()
{
std::cout << sizeof( B ) ;
}
结果是1(VC ++ 2010)
在我看来,该类实际上不需要任何内存,但是对象不能为零大小,因为如果你以其地址为例,这将没有语义意义。 Ferruccio的答案证实了这一点。
答案 4 :(得分:0)
我从现在开始说的所有内容都依赖于实现 - 但大多数实现都符合。
如果类有任何虚方法,则会有一个不可见的vtable指针成员。但是,你的例子并非如此。
是的,编译器会将成员函数调用视为与自由函数调用相同,除非它是虚函数。即使它是一个虚函数,如果编译器在调用时知道具体类型,它也可以绕过vtable。每个调用仍然依赖于对象,因为有一个不可见的this
参数,对象的指针会被添加到调用中。
答案 5 :(得分:0)
我认为它们看起来就像C ++中的任何对象:
非虚拟函数在类中根本不占用任何空间。相反,它们可以被认为是这样的函数:
int B_FuncA(B *this, int x);
int B_FuncB(B *this, int y);
如果其他.cpp
文件可以使用此类,我认为这些将成为实际的类实例,而不是常规函数。
如果您只希望自己的函数是免费的而不是绑定到对象,则可以make them static
或use a namespace
。
答案 6 :(得分:0)
我被告知非虚拟成员函数最终编译为自由函数,与声明它们的类的实例完全无关(虚函数也是如此,但对象存储vtable与函数指针)。访问限制仅仅是语义上的“人”级别。只有类的数据成员(和vtable等)实际上构成了对象的内存结构。
是的,这通常是它的工作原理。可能值得指出标准中未指定的区别,并且它不是 required - 在编译器中实现这样的类是有意义的。
再说一次,B类对象在内存中是什么样的?它是某种占位符价值吗?必须有东西,我可以拿对象的地址
完全。 :) C ++标准要求对象占用至少一个字节,正如您所说的那样。它必须有一个地址,如果我把这些对象放到一个数组中,我必须能够增加一个指针以获得“下一个”对象,所以每个对象必须有一个唯一的地址并占用至少1个字节。 (当然,空对象 不能正好占用1个字节。出于性能原因,一些编译器可能会选择将它们设为4个字节或任何其他大小)
合理的编译器甚至不会使它成为占位符值。为什么要在这个字节中写入任何特定值呢?我们可以让它包含创建对象时所持有的任何垃圾。它永远不会被访问。只分配一个字节,从不读取或写入。