动态绑定虚拟功能

时间:2011-02-25 18:17:29

标签: c++

class base {
public:
    virtual void foo()
    {
         cout << "Base class virutal function " << endl;
     }
}

class Derived : public base {
public:
    void foo()
     {
          cout << "Derived class virtual function " << endl;


int main()
{
    Base b, *ptr;
    Derived d;

    ptr = &b;
    ptr->foo();
    ptr = &d;
    ptr->foo();
}

您好, 我对这里的dymnamic绑定有疑问。因为编译器知道当b.foo()存在时它可以使用基本虚拟fumction。当d.foo()存在时,它可以使用foo的派生版本。我的意思是编译器在编译期间有一些信息,但仍然有文献说在运行时决定使用哪个函数。

3 个答案:

答案 0 :(得分:5)

特定的案例 1 中,编译器(至少在理论上)可以确定在每种情况下调用哪个函数,并生成代码以简单地调用这两个函数直接(当我测试它时,大多数编译器完全按照这种方式优化代码)。

更典型的多态性案例涉及某种用户输入,因此无法静态确定要调用的函数。例如,使用您的BaseDerived类,请考虑以下内容:

int main(int argc, char **argv) {
    Base b;
    Derived d;

    Base *arr[] = {&b, &d};

    int i = atoi(argv[1]) != 0;
    arr[i]->foo();
    return 0;
}

在这种情况下,编译器无法确定要静​​态调用的正确函数 - 根据您在运行时在命令行上传递的内容,它可能使用Base或者foo()的派生版本。

您似乎也有一种中间案例,您开始尝试将其包含在代码中,但从未真正完成 - 您初始化ptr以指向您的Base对象,然后指向您的Derived对象,但你永远不会通过ptr调用函数,只能直接在对象本身上调用。如果您通过指针调用了函数,那么优化比仅使用具体对象直接进行优化更难。在这种情况下,较少的编译器将静态地确定类型,但至少有一些仍然可以/将。

1 嗯,几乎这个具体案例无论如何。就目前而言,代码将无法编译,因为您已经定义了一个名为base的类(小写'b')并尝试实例化一个名为Base的类(大写) 'B')。此外,您的“派生”类实际上并非来自Base,正如您可能想要的那样。一旦修复了......

答案 1 :(得分:5)

在你给出的具体例子中,你是对的;编译器有足够的信息来知道在编译时调用哪个函数。因此编译器不必在运行时查找该函数,但这是一个不影响程序结果的编译器优化 - 编译器可以自由地绕过查找。

答案 2 :(得分:2)

您是说编译器可以注意您将d转换为Base *ptr并在运行时解析实际的函数地址吗?

如果是,样本在哪里:

if (rand() > 0.5)
{
    ptr = &b;
}
else
{
    ptr = &d;
}

ptr->foo();

编译器如何在运行时知道地址?这就是动态绑定的原因。