首页 > 试题广场 >

在32位操作系统gcc编译器环境下,下面程序的运行结果为?

[单选题]
在32位操作系统gcc编译器环境下,下面程序的运行结果为()
#include <iostream>
using namespace std;
class A {
public:
    int b;
    char c;
    virtual void print() {
        cout << "this is father’s fuction! " << endl;
    }
};
class B: A {
public:
    virtual void print() {
        cout << "this is children’s fuction! " << endl;
    }
};
int main(int argc, char * argv[]) {
    cout << sizeof(A) << "" << sizeof(B) << endl;
    return 0;
}

  • 12 12
  • 8 8
  • 9 9
  • 12 16
推荐
答案:选A
答案解析:类的大小只与成员变量(非static数据成员变量)和虚函数指针有关,还要考虑到对齐.
那么类A的大小等于4个字节 + 4个字节(考虑对齐) + 4个字节(指向虚函数的指针)=12字节;
类B的大小就是等于类A的大小12个字节.
因为在基类中存在虚函数时,派生类会继承基类的虚函数,因此派生类中不再增加虚函数的存储空间(因为所有的虚函数共享一块内存区域),而仅仅需要考虑派生类中添加进来的非static数据成员的内存空间大小。所以类B大小为12B

编辑于 2014-12-30 15:07:10 回复(6)
类B虚拟继承类A。
A中的内存方式是:4(int)+4(char对齐)+4(A中的虚指针)=12
B中的方式是:4(A::int)+4(A::char对齐)+4(B中的虚指针)=12
其中A的虚指针和B的虚指针不一样,并且各种的虚函数表也不一样。

如果将class B:public A 改成 class B:virtual public A
则B中会多一个指向虚继承的指针:12+4(Ptr_B->A)=16。

如果再 class B中,多定义一个A中没有的虚函数,则又多4字节。不清楚具体是什么内容,猜测是B中又多了一个虚函数表。

各种复杂,累了,醉了。
编辑于 2015-04-01 16:10:07 回复(10)
对于本题,我还是比较熟悉的。错选是因为只想起了内存对齐,忘记了除了先对齐之外,还有末尾的补齐。
无论是用微软的MSVC编译器还是GCC,只要有虚函数,那么虚指针一定是在对象的起始位置。
用事实说话。二者占用内存均为12个字节。
查看类的内存布局,可知:
class A size(12):
        +---
 0      | {vfptr}
 4      | b
 8      | c
        | <alignment member> (size=3)
        +---
class B size(12):
        +---
        | +--- (base class A)
 0      | | {vfptr}
 4      | | b
 8      | | c
        | | <alignment member> (size=3)
        | +---
        +---
默认情况下,编译器的对齐系数为8
内存对齐:就是每个成员的起始位置必须是 对齐系数与成员自身大小 二者中较小者 的整数倍。
内存补齐:取结构体或类的成员中最大的那个值,与对齐系统相比,取二者中的较小者。然后保证整个对象结尾地址的下一个地址是较小者的整数倍。
对于该题,记对象起始地址为0字节处, 类A的大小是首先虚指针的大小,4个字节(地址0-3),接着b,4个字节(4-7),然后是c,1个字节(8)。对齐完成。该补齐了。,那么没有补齐时,现在对象的结尾地址的下一位是9,而对象中最大成员的大小为4,结尾地址的下一个地址要是4的倍数。现在已经是9了,故最小需要为12,所以需要补上3个字节(9-11)。也就是说,对象A占用0到11共12个字节。
对于B也是一样的。参考我上面的类的内存布局图即可明白。
切记,不只有内存对齐,还有补齐。
发表于 2015-12-14 18:29:15 回复(2)
输出结果:


总结:空类占一个字节,系统安插了一个char类型。
           类中含有虚函数时(无论有多少个虚函数),都只占用一个指针的大小,原因是系统多用一个类的指针维护虚函数表。
           发生虚继承时,编译器会为该类安插一个指向父类的指针,多个父类时(虚继承)会有多个这样的指针。
发表于 2019-01-06 20:29:25 回复(2)

这题考查了1.内存对齐 2.虚继承与虚函数继承的区别。只有虚继承(virtual public)才会继承基类的虚函数表,这样答案就是12,16.

发表于 2017-04-21 11:17:38 回复(0)
注意,结构体和类在计算空间大小时,都要考虑对齐问题
发表于 2019-07-05 09:45:34 回复(0)
1)类的大小只与成员变量(非static数据成员变量)和虚函数指针有关,还要考虑到对齐.
2)那么类A的大小等于4个字节 + 4个字节(考虑对齐) + 4个字节(指向虚函数的指针)=12字节;
     类B虽然继承A,但是因为所有的虚函数共享一块内存区域,派生类中不再增加虚函数的存储空间,所以其大小仍然等于类A的大小12个字节.
仅仅需要考虑派生类中添加进来的非static数据成员的内存空间大小。
发表于 2019-04-11 19:26:01 回复(0)
如果是虚继承的时候,还是会增加一个指向虚继承的指针,即多4字节。例如class B : virtual class A的时候,B中多一个A中没有的虚函数时,B的大小还会增加4。(32位系统)
发表于 2017-01-12 11:53:08 回复(1)
虚函数指针,不管你有多少个,一个类就只记一次
不管你继承多少层,一个类就只记一次
so....A
发表于 2016-11-15 09:43:30 回复(4)
只有虚继承才会继承基类的虚函数表
发表于 2023-10-17 16:23:38 回复(0)
只有虚继承(virtual public)才会继承基类的虚函数表,这样答案就是12,16.
发表于 2022-09-26 14:18:47 回复(0)
《深度探索C++对象模型》第3章 Data语意学 有详细说明
发表于 2022-05-26 17:02:09 回复(0)
sizeof(class) = sizeof(int) + sizeof(char) + sizeof(vptr) + alignment
虚函数指针存在vtbl中,不计算在内
发表于 2020-07-23 19:22:42 回复(0)
"派生过程中所有函数共用一段内存"是否可以解释为:虚函数经过override之后被覆盖掉,因此内存大小和位置都不变
发表于 2020-02-28 21:29:43 回复(0)

对齐了解,为什么虚函数指针占4字节


编辑于 2019-11-21 10:00:50 回复(0)
一定要注意对齐,int 与char的位置不同会导致sizeof得到的结果也不一样,另外还要注意指针所占内存
发表于 2019-09-11 21:58:18 回复(0)
所有的虚函数共享存储空间
发表于 2019-07-08 12:54:09 回复(0)

定义了一个虚函数就会有一个this指针指向这个虚函数在这个类里面


发表于 2019-03-23 13:24:46 回复(0)
派生类只进行了对虚函数的重写,没改变原有大小
发表于 2019-03-21 22:29:11 回复(0)

类的大小只与类的成员函数和虚函数指针大小有关。sizeof(A)的大小等于4(int)字节+4(char考虑对齐)字节+4(指向虚函数的指针)字节 
sizeof(B)的大小等于 4字节(int)+4字节(char考虑对齐)+4字节(指向虚函数的指针)

为什么sizeof(B)不是加上了两个虚函数指针的大小呢?为什么不是16?

因为在基类中存在虚函数时,派生类会继承基类的虚函数。在派生类中多定义了一个基类中没有的虚函数。派生类不会再增加字节(所有的虚函数共享一块存储空间一个虚函数表)仅仅需要考虑派生类中加进来的非static数据成员的内存空间大小即可。所以B的大小也为12。

发表于 2018-04-26 09:06:21 回复(0)
A,B共用一个虚表
发表于 2018-04-20 15:32:19 回复(0)