2016-08-13 126 views
-1

使用关键字virtual时,如果compliler-linker知道调用者和被调用者的位置(地址/偏移量保存在表中等),那么所有地址都可以在exe中被硬编码。那么它不应该被称为早期绑定。如果仅在执行调用者代码(操作系统中的地址?)时获得地址,则这必须是真正的后期绑定。如果后期绑定是首选,为什么编译器 - 链接器不想使用它(不管源代码是否使用了虚拟关键字)?萨姆早期和晚期绑定是如何实现的?

+3

目前尚不清楚你在说什么。你似乎在混淆C++多态和库链接。这些是不同的事情。 –

+2

'如果compliler-linker知道调用者和被调用者的位置(地址/偏移保存在表中等),那么所有地址都可以在exe中被硬编码 - 如果可以的话。一般情况下它不能。然后它只是一个函数ptr(在表中)。 – lorro

回答

2

考虑这个例子:

#include <iostream> 
#include <memory> 

class Base { 
public: 
    virtual void foo() = 0; 
}; 

class Derived1: public Base { 
public: 
    virtual void foo() { std::cout << "impl1" << std::endl; } 
}; 

class Derived2: public Base { 
public: 
    virtual void foo() { std::cout << "impl2" << std::endl; } 
}; 

int main() { 
    int c; 
    std::cin >> c; 
    std::unique_ptr<Base> inst; 
    if (c) inst.reset(new Derived1()); 
    else inst.reset(new Derived2()); 
    inst->foo(); 
} 

在这里,你不知道哪个FOO()实现调用,直到你真正运行的程序。所以是的,C++有真正的晚期绑定。

后期绑定的不利之处在于,当调用虚拟方法时存在一个很小的开销。由于C++可以用在一些超级优化的计算库中,所以决定是否使用它是留给程序员的。

正如Matteo Italia在评论中指出的那样,虚拟方法可以防止内联。这可能会对性能产生显着影响(与通话开销不同,后者几乎从不会被注意到)。

+0

关于虚拟通话费用:与常规通话相比,虚拟通话本身通常并不昂贵(只要对分支预测器而言“容易”),通常很大的成本就是错失了内联机会。我不得不在内部循环中删除虚拟呼叫,在某些情况下可以获得2倍或更多的加速。 –

2

如果在呼叫者代码被执行仅获得地址(从操作系统地址?)

它不来自于操作系统,但是从(有效)的函数的指针。

那么这必须是真正的晚期绑定。

它是。

如果后期绑定是首选,为什么编译器,链接器并不一定要使用它(不考虑如果源代码中使用的虚拟关键字,或者不是)?

那么,这不是首选。速度非常慢。这不一定是因为“物理”函数调用花费的时间比正常的要长很多;由于额外的间接方法需要更长的时间,但真正的不利之处在于你的调用无法完全消除(通过内联),因为编译器不知道哪个函数最终会在运行时被调用。

除非您需要它,否则您不想使用它,即您需要虚拟呼叫。

这个决定与您在“我应该只是调用一个函数还是应该从一堆选项中查找映射中的函数指针并调用我想要的函数指针那?”您使用正确的工具来完成这项工作,但额外的灵活性会带来成本。

+0

@DavidHaim:是的,这使得它在我的书中“非常慢”:)对内联等等说再见。当然,实际上量化是一件复杂的事情。 –

+0

我会澄清它。 –

相关问题