C++ 编译器如何决定何时使用vPtr调用函数
如何确定vptr是否将用于调用虚拟函数 考虑以下层次结构:C++ 编译器如何决定何时使用vPtr调用函数,c++,C++,如何确定vptr是否将用于调用虚拟函数 考虑以下层次结构: class A { int n; public: virtual void funcA() {std::cout <<"A::funcA()" << std::endl;} }; class B: public A { public: virtual void funcB() {std::cout <<"B::funcB()" << std::e
class A
{
int n;
public:
virtual void funcA()
{std::cout <<"A::funcA()" << std::endl;}
};
class B: public A
{
public:
virtual void funcB()
{std::cout <<"B::funcB()" << std::endl;}
};
A* obj = new B();
obj->funcB(); //1. this does not even compile
typedef void (*fB)();
fB* func;
int* vptr = (int*)obj; //2. Accessing the vptr
func = (fB*)(*vptr);
func[1](); //3. Calling funcB using vptr.
A类
{
int n;
公众:
虚空funcA()
{std::cout在Barry的评论中添加一行virtual void funcB()=0;
到class A
似乎可以解决问题。因此,您的问题有两个答案:
简短的是:
obj->FuncB()
只是一个合法调用,如果obj
(在本例中为a
)的静态类型有一个带有适当签名的函数FuncB
(直接或由于基类)。只有在这种情况下,编译器才决定将其转换为直接函数调用还是动态函数调用(例如,使用vtable),这取决于a
的声明(或其基本类型)中FuncB
是否声明为虚拟
较长的是:
当编译器看到obj->funcB()
时,它无法知道(优化除外),obj的运行时类型是什么,尤其是它不知道实现funcB()
的派生类是否存在。obj
可能是在另一个翻译单元中创建的,或者可能是一个函数参数
不,该信息通常不存储在虚拟函数表中:
vtable只是一个地址数组,如果事先不知道特定的加法对应于一个名为funcB
的函数,编译器就不能使用它来实现调用obj->funcB()
-或者更准确地说:标准不允许这样做。这种先验知识只能通过静态类型的obj
(或其基类)中的虚拟函数声明提供
原因,为什么调试器中有这些信息(其行为超出了标准)因为它有访问调试符号的权限,通常不属于分布式发布二进制。在默认情况下,将这些信息存储在VC++中,会浪费内存和性能,因为程序不能以标准C++的方式使用。不同的故事
(2)后面的行显示未定义的行为。“似乎有效”是未定义行为的一种可能表现形式。当然,它不会编译。没有A::funcB()<代码> >代码>编译器如何决定使用VTABLE调用函数?< /代码>当决定满足C++语言的规定语义时,它决定这样做。为什么你要关心这些实现细节?你想解决什么问题?在<代码> Obj>函数()中
,因为编译器知道,obj
实际上指向A
的一个实例,或者从A
派生的另一个类C
的一个实例。没有迹象表明B
在图片中的任何地方,对funcB
的调用是有意义的。@IgorTandetnik你是什么意思“在obj->funcB();,因为编译器知道obj实际上指向从A派生的另一个类C的实例。“没有回答问题。@匿名:欢迎您-如果您认为它完全回答了您的问题,请随意接受它。@MikeMB因此,关于可能的优化,您或多或少可以说,如果您调用方法的对象已知(通过某种优化)与其指针的类型相同(即没有进行上转换)函数调用可以静态地解析,否则,它可以被上转换,所以我们最好参考vtable(以多态方式解析)?@DomFarolino:没错,这就是所谓的设备化