有件事我还是不明白。
对于我声明的每个类,都有一个隐藏的vptr成员指向类虚拟表。
假设我有这样的声明:
class BASE
{
virtual_table* vptr; //that's hidden of course , just stating the obvious
virtual void foo();
}
class DERIVED : public BASE
{
virtual_table* vptr; //that's hidden of course also
virtual void foo();
virtual void cho();
}首先,我想了解一些事情,派生的和基础的vptr的成员名是否真的相同?
第二,在这种情况下会发生什么:
base* basic = new derived();我明白了,基本变量得到的是vptr,但是这是怎么发生的呢?原因通常在发生转换时,应将派生的基本部分(包括基本的vptr)分配给基本部分,而不是派生的vptr。如果两个类中有一个同名的变量,可能会有所不同,我不知道。
第三个也是最后一个问题:当我有
base* basic = new derived();有没有办法调用basic -base的成员函数,即使它是虚拟的?
谢谢
发布于 2009-12-02 17:19:08
首先,是的,它是同一个成员。它在运行基本构造函数时第一次自动分配,在运行派生构造函数时第二次分配。(在默认为空构造函数的情况下,对base的无用赋值将被优化。)
第二,没有真正的转换。事实上,派生可以被命名为“是一种”关系。在这种情况下,派生的“是”基。如果考虑派生对象的内存的第一个字节,它们与基对象的第一个字节具有相同的含义。
第三,可以按如下方式调用基本成员函数:basic->base::foo();
发布于 2009-12-02 17:23:27
首先,虚拟表不是C++标准的一部分。C++编译器可以自由地以任何他们认为合适的方式实现虚函数。通常他们会使用虚拟表,这是真的;但在这种情况下,他们可以以任何他们认为合适的方式实现它们。
在大多数常见的实现中,basic不会获得derived的vptr;*basic的vptr将指向derived的vtable,这实际上并不相同。basic只是一个指针,它所指向的对象有一个vptr。不涉及转换。在任何情况下,<代码>D9只是一个实现细节的内部名称。没有真正的类成员称为<代码>D10。
而且,只要用类名(在本例中为basic->BASE::foo())限定基类函数,就可以调用任何基类函数。
更新:为了记录起见,我尝试使用名为__vfptr (这是此编译器中vptr的内部名称)的指针在VC++2008中创建一个类,它可以正常工作,即使调试器被变量名搞糊涂了。
发布于 2009-12-02 17:18:36
vtable (用您的话说是virtual_table)将指向BASE和DERVIVED的不同地址,前提是DERIVED覆盖了至少一个来自BASE的虚拟函数。但是,BASE的每个实例都有相同的vtable指针(DERIVED也是如此)。
当你这样做的时候:
someobject->foo();这将转换为:
someobject->vtable[COMPILER_GENERATED_OFFET_FOR_FOO]();vtable是一个函数指针数组,其中某个虚函数(比如foo)的偏移量对于类层次结构中的所有类都是相同的。
https://stackoverflow.com/questions/1831635
复制相似问题