一个C++的问题(200分)

  • 主题发起人 主题发起人 expect
  • 开始时间 开始时间
E

expect

Unregistered / Unconfirmed
GUEST, unregistred user!
class base {
virsual void sub() {}
};

class derived :public base {
void sub() {}
void foo() {}
};

main() {
base * b =new derived
//1
b->sub()
//2
b->foo()
//3
(derived *)b->foo()
//4
};

请问:
步骤1:中 base和derived在内存中的表现形式是怎样的?
(有人说:derived 紧跟在base 的后面,b 指向base头部)
步骤2:中 c++是如何实现的,调用的是 derive::sub,而不是
base::sub。
步骤3:中 c++是如何判断foo不存在的。
步骤4:中 b是否发生过变化。
 
1. base 和 derived 彼此在内存中的位置是独立的,并不需要相互联系

2. base 和 derived 类各自都包含有一个虚拟方法表,其中存储了指向虚拟
函数的指针。
在你的例子中指针b虽然定义成 base * ,但其实际指向地址是一个derived
对象的头部,所用到的虚拟方法表仍旧是derived 类的,当然最终查到
sub()函数指针指向的是derived::sub()

3. 第3句是错误的,这一错误由编译器负责指出,因为编译器并不知道b
实际指向一个derived对象,看下面这段代码就很明显:

func(const base* b)
{
b->foo();
}
func的参数可以是一个base对象,也可以是derived对象,编译器无法确定
b是否具有foo()这一函数,所以干脆在执行类型检查时一律参照所定义的
类型

4 (derived *)b->foo()
中 b 并没有变化,指针还是那个指针,指向的地址还
是那个地址,只不过执行了类型强制转换后向编译器保证b指向的是个
derived类型(或者是derived 的子类)的对象,这样才能通过编译期间的
类型检查

关于对象在内存中的layout问题,可以去看《深入探索C++对象模型》,
CSDN上的C/C++版也有过相当充分的讨论
 
你去小富翁找答案
 
其实,我就有一点不明白:通过 b 指针找到 derived 的虚拟方法表,这时编译器是不是

要对 derived 的虚拟方法表和 base 的虚拟方法表进行比较呢?如果此时调用的

方法(foo)在 derived 中的编号大于在 base 中的编号就不执行,如果不大于就执行

derived 的方法。

 
对于你前面的几点cheka说明得很清楚。

方法foo不存在执不执行应该如cheka所述编译报错,因为b声明为一个base类,这个类
没有foo成员函数。

但由于b实际指向了一个derived的类(new derived决定)所以,它的vmt copy derived类的vmt(这个过程由c++动态联编机制完成)
所以b->sub()执行的是derived::sub().

(derived *)b->foo():由于对b进行了强制类型转换所以编译能通过,但如果没有b=new derived();运行时会出错。


 
原谅我有点转牛角尖,

>>方法foo不存在执不执行应该如cheka所述编译报错,因为b声明为一个base类,这个类
没有foo成员函数。

c++编译器应该有所依据的编译报错,我想知道他的依据是什么?
 
依据很简单啊, 编译器无论如何总能判断你在定义base类时,并没有定义它有
foo这个成员函数吧
 
我今天无意中看到一本书,关于c++编译器原理的,作者是c++编译器的设计者之一.
并且时侯杰翻译的.应该不错,我还没有来得及仔细看.
 
接受答案了.
 
Note that VMT doesn't retain any pointer to non-virtual function, the compiler
select appropriate function in compile time, which is fully determined by the
type of the variable.
 
后退
顶部