C++ 编译器如何决定何时使用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

如何确定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::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:没错,这就是所谓的设备化