C++ 理解虚函数有困难
及 我读到,C++ 理解虚函数有困难,c++,C++,及 我读到,h指针将指向它所指向的对象的vtable,并因此调用该函数?但这是如何在运行时实现的呢 除非确定正在执行的操作,否则不应尝试访问vtable指针。就我们通常用来定义程序含义的语言而言,vtable甚至不存在。这是一个实现细节,它属于实现(也称为编译器和运行时环境) 如果实现受到可移植ABI(应用程序二进制接口)的约束,那么ABI将说明在哪里找到vtable指针以及vtable内的内容reinterpret_cast(my_obj)应该能够从任何“合理”ABI上的对象获取指针 这样一个
h
指针将指向它所指向的对象的vtable,并因此调用该函数?但这是如何在运行时实现的呢
reinterpret_cast(my_obj)
应该能够从任何“合理”ABI上的对象获取指针
这样一个程序将被限制在一个平台和一个ABI上。(C++ABI接口的变化频率往往比C语言高,但比其他语言低。)依赖ABI是一个糟糕的设计选择,除非你只是想证明自己疯了dynamic_cast
用于确定派生和查找派生对象的算法实际上可能非常慢,而不是O(1)。它通常必须搜索基类的链接结构好的,你的第一个问题:我给你举个例子,可能会更好的理解! p1将指向vtale1,p2将指向vtable2,p3将指向vtable3,如果调用某个虚拟函数,它将找到虚拟表并获取地址 在代码中:
Base1 *p1 = new Derive();
Base2 *p2 = new Derive();
Base3 *p3 = new Derive();
h将指向Y的内存的起始位置,即X的虚拟表,他将找到在Y中实现的abc()
的地址
你的第二个问题:
编译器会考虑成员函数作为常态函数,因此将成员函数的地址放在<代码>代码段中,所以它不占用内存!p> 如果您想读取虚拟表,可以这样尝试:我在gcc4.7中的示例中尝试了这种方法
X *h = new Y;
我是否可以阅读这个虚拟表格
不是真的,不是不知道指针相对于对象指针值的位置,对象指针值是特定于编译器的
如果没有,至少可以访问虚拟指针
为什么??您可以通过h->abc
获取函数的地址,这就是您想要的吗
另外,当我调用h->abc()时,它如何知道h所指向的类的对象
它实际上不知道,它只知道该类的vtable在哪里。如果使用RTTI,vtable中有信息可以告诉它是什么类,但是调用虚拟函数并不需要这些信息。从X派生的每个类都有自己的vtable,其中包含自己的虚拟函数指针。(当然,始终假定基于vtable的实现。)
我读到,h指针将指向它所指向的对象的vtable,并因此调用该函数?但这是如何在运行时实现的呢
你刚才自己也描述过。仅稍微详细说明一下,指针h->abc
解析为h->\u vtable[x]
,表示abc
的虚拟函数指针vtable中的偏移量的某个常量x
。因此,调用解析为*(h->_vtable[abc])(…)
另一个问题,与虚拟函数无关,我需要澄清一下。若函数和其他变量一样有地址,为什么它们不占用对象中的空间呢
他们为什么要这样做?这意味着每个对象中的每个函数都有一个副本。重点是什么?我将编辑最后一个问题,因为它与讨论的主题不符。但我相信前两个问题完全在讨论范围之内。
X *h = new Y;
h->abc();/* This would call the abc function in Y*/
#include<iostream>
using namespace std;
class Base1 {
public:
int ibase1;
Base1():ibase1(10) {}
virtual void f() { cout << "Base1::f()" << endl; }
virtual void g() { cout << "Base1::g()" << endl; }
virtual void h() { cout << "Base1::h()" << endl; }
};
class Base2 {
public:
int ibase2;
Base2():ibase2(20) {}
virtual void f() { cout << "Base2::f()" << endl; }
virtual void g() { cout << "Base2::g()" << endl; }
virtual void h() { cout << "Base2::h()" << endl; }
};
class Base3 {
public:
int ibase3;
Base3():ibase3(30) {}
virtual void f() { cout << "Base3::f()" << endl; }
virtual void g() { cout << "Base3::g()" << endl; }
virtual void h() { cout << "Base3::h()" << endl; }
};
class Derive : public Base1, public Base2, public Base3 {
public:
int iderive;
Derive():iderive(100) {}
virtual void f() { cout << "Derive::f()" << endl; }
virtual void g1() { cout << "Derive::g1()" << endl; }
};
Base1 *p1 = new Derive();
Base2 *p2 = new Derive();
Base3 *p3 = new Derive();
X *h = new Y;
typedef void(*Func)(void);
Derive d;
int **pd = (int **)(&d);
int i = 0;
while(i < 4)
{
Func f = (Func)pd[0][i];
f();
i++;
}
int s = (int)(pd[1]);
cout << s << endl;
i = 0;
cout << "===============================================" << endl;
while(i < 3)
{
Func f = (Func)pd[2][i];
f();
i++;
}
s = (int)(pd[3]);
cout << s << endl;
cout << "===============================================" << endl;
i = 0;
while(i < 3)
{
Func f = (Func)pd[4][i];
f();
i++;
}
s = (int)(pd[5]);
cout << s << endl;
s = (int)(pd[6]);
cout << s << endl;
Derive::f()
Base1::g()
Base1::h()
Derive::g1()
10
===============================================
Derive::f()
Base2::g()
Base2::h()
20
===============================================
Derive::f()
Base3::g()
Base3::h()
30
100