首页 > 试题广场 >

观察下面一段代码: class ClassA { publi

[单选题]
观察下面一段代码:
class ClassA {
  public:
    virtual ~ClassA(){};
    virtual void FunctionA(){};
};
class ClassB {
  public:
    virtual void FunctionB(){};
};
class ClassC : public ClassA, public ClassB {
  public:
};

ClassC aObject;
ClassA *pA = &aObject;
ClassB *pB = &aObject;
ClassC *pC = &aObject;


关于pA,pB,pC的取值,下面的描述中正确的是:
  • pA,pB,pC的取值相同.
  • pC=pA+pB
  • pA和pB不相同
  • pC不等于pA也不等于pB
推荐
如果我们输出三个指针的值。
上面的代码在我的电脑上输出
0x7fff502f5aa8

0x7fff502f5ab0

0x7fff502f5aa8


可以看到pA和pC是相同的。
所以选择C。

实际上,在这个情况下,子类的指针和第一个基类的指针应该是一样的,和第二个基类是不一样的。

编辑于 2015-02-02 14:21:55 回复(15)
注意到题目中class ClassC : public ClassA,public ClassB,即A在前,B在后,所以

更多详情,请见http://pan.baidu.com/s/1jHKcqb0
发表于 2016-04-03 08:41:25 回复(4)
发表于 2015-06-03 21:34:13 回复(2)

本题中,ClassA* pA=&aObject;

ClassB* pB=&aObject;

ClassC* pC=&aObject;

这三行代码实际等价于:

ClassA* pA=static_cast<ClassA*>(&aObject); ClassB* pB=static_cast<ClassB*>(&aObject); ClassC* pC=&aObject;
假设ClassA的内存地址块是1,ClassB的内存地址块是2,则ClassC的内存包含了1和2,
而取地址操作通常指的是取首地址,即pA指向ClassA的首地址,
pB就指向了ClassB的首地址,由于ClassC采用的是多继承的方式,
继承ClassB后,pC指向的首地址与pA一样。
通过上面分析可知,pA与pC取值相同,pA与pB取值不相同。
因此,选项C正确,选项A、选项B与选项D错误。

所以,本题的答案为C。


编辑于 2018-07-13 17:29:24 回复(3)
http://blog.csdn.net/haoel/article/details/3081328/
陈皓的博客有详细解释:
多重继承时,以声明顺序在内存中存储A/B的空间(即虚表+数据),再存储C的数据;C中重新实现的虚函数会在A/B的虚表中取代原有的虚表项,C中新加的寻函数会加在A中虚表的最后。
发表于 2015-09-06 16:16:07 回复(3)
这题考察是对象模型中的内存布局。首先明确的是指针都是指向class c,这里需要知道class c中的内存分布情况;class c中继承顺序为A,B,而且不是虚继承,故其对象模型内存是先是,A的内容(虚函数指针),然后B的内容,最后 c对象自己的内存 。这样就知道pa=pc,pc!=pb。
编辑于 2015-09-07 17:54:43 回复(8)

1.归根到底本题还是考查指针的偏移量的问题。

根据多继承下含有virtual function时的数据布局的知识我们可以画出一个ClassC类对象的数据布局:
图片说明
当执行ClassA* pA=&aObject;时就是执行地址值的简单赋值动作,将aObject对象的首地址赋值给pA指针;
当执行ClassB* pB=&aObject;时,需要下面的内部转化,实际上是在计算偏移量

//伪码如下
ClassB* pB = (ClassB*)((char*)&aObject + sizeof(ClassA))
//所以在32位操作系统下,pB与pA和pC相差4;在64位操作系统下,相差8;相差的值即为vptr指针的值。

当执行ClassC* pC=&aObject;时也是执行地址值的简单赋值动作,将aObject对象的首地址赋值给pC指针;

2.解析本题答案之后,我们来补充一个重要的概念:出现在derived class中的base class subobject是否具有其完整原样性。

先上代码:

#include 
using namespace std;
class BaseClass
{
private:
    int a;
    char b;
};
class SubClass :public BaseClass
{
private:
    char c;
};
int main()
{
    SubClass obj2;
    cout << sizeof(obj2) << endl;   //8
    return 0;
}

上述代码在Code::Blocks下的g++编译器下答案是8;但是呢在VS下的VC++编译器下答案为12;那么为什么会是这样呢?

原因是这样的:在gcc编译器中,派生类定义的对象的数据布局的基类部分不具有完整原样性,也就是说在一个SubClass子类对象中,它自身的非静态数据成员c占用基类部分填充的三个字节的第一个字节。所以一个SubClass类对象和一个BaseClass类对象占用的空间一样的;但是在VC++编译器中,派生类定义的对象的数据布局的基类部分具有完整原样性,一个SubClass子类对象中,它自身的非静态数据成员c不占用基类部分填充的三个字节,所以一个SubClass子类对象所占空间为基类部分的大小加上c的大小加上填补的三个字节;

为什么需要补充这个知识点呢?因为这道题目各个类中没有非静态成员变量,况且没有涉及到虚继承,将问题简单化。但是如果在指定具体编译器和操作系统的位数下,根据编译器选择的不同或者操作系统的位数不同,可能各个类对象的所占的空间会不一样,各个类对象的数据布局也就不一样。

参考书籍《《深度探索C++对象模型》》

发表于 2019-10-17 16:04:09 回复(0)
首先,pA,pB,pC均为指针,Object为对象。
pA=&Object,即指针pA指向Object的地址,因此可以看为正常的虚函数实例(基类指针指向子类对象)。
因为类A与类B的虚函数不同,因此类A与类B的虚函数表也不相同。
因为有虚函数表,c继承的时候两个虚函数表都继承过来了,父类指针指向子类的时候需要偏移到自己的位置,所以pA!=pB。
而因为C首先继承A,再继承B(可以认为前一半是a,后一半是b),因此,pA指针指向c的时候,就刚好指向初始地址,则pA=pC,而pB指向c的时候需要移动到后一半,所以pB!=pC
发表于 2021-07-12 15:23:50 回复(0)
感觉题目的设置模棱两可。没有让做题人明白出题意义。到底想考察的内容。下面的解释者给出的答案也是在凑答案。
发表于 2021-02-21 20:30:09 回复(0)
发表于 2016-03-05 16:52:03 回复(0)
C多重继承自A和B,A和B两个基类都有两个虚函数表,其中按照继承顺序,A的虚函数表排在B的虚函数表前面,则选择C。
大概如下:  aObject的地址从A的虚函数表开始,然后到B的虚函数表,再到C自身的成员。
发表于 2015-08-20 20:04:28 回复(1)
D
需要好好在读一下虚函数的内存布局。
发表于 2015-01-09 17:30:30 回复(0)
题目描述不太恰当,说的是对对pA,pB,pC的取值,

刚开始考虑的是 上图所示的情况,若指针释放空间时可以释放的空间,则是其取值。
发表于 2023-08-20 11:24:22 回复(0)
在多继承没有覆盖的情况下,子类的虚表会紧跟第一个父类的虚表,其他的父类虚表中不会出现子类的虚表
发表于 2018-04-24 11:09:05 回复(0)
子类有多个父类,子类的指针和第一个基类的指针应该是一样的,和第二个基类是不一样的。
发表于 2017-09-04 16:30:34 回复(0)
这题考察指针比较的含义。
对象指针的比较的实质不是地址比较,而是对象同一性问题,即这些指针是不是指的同一个对象。
c++对象有多个有效地址,虽然他们地址值不相等,但是下面判断为真
if(pa == pc)...
if(pb == pc)...
发表于 2016-07-02 18:01:33 回复(1)
先看下结果,可以看出 pB 不包含class A的虚函数指针
pA: 0x7ffe2a7b5a60
pB: 0x7ffe2a7b5a68
pC: 0x7ffe2a7b5a60
发表于 2018-04-23 23:06:26 回复(0)
    基类指针指向派生类对象,所指向的位置是基类成员在派生类对象中的所处位置(而不一定是整个派生类对象的起始位置)。基类成员的内存顺序,是和继承时的声明顺序相对应的。
    这和virtual没有关系,即使没有虚函数、虚继承,只有普通数据和函数,继承时内存模型也是这样。只不过有虚函数或者虚继承的时候,会多一个虚表指针或者虚基类指针成员。
编辑于 2023-12-20 18:51:58 回复(0)
A与B之间没有继承的关系所以不存在重写,因此A不等B

发表于 2023-11-14 21:27:07 回复(0)
发表于 2022-04-02 21:25:27 回复(0)
子类的指针和第一个基类的指针应该是一样的,和第二个基类是不一样的
发表于 2022-03-15 11:12:30 回复(0)