C++ 中的动态调度和后期绑定有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20187587/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between dynamic dispatch and late binding in C++?
提问by Vardit
I've recently read about the Dynamic Dispatch on Wikipediaand couldn't understand the difference between dynamic dispatch and late binding in C++.
我最近在维基百科上阅读了动态调度,但无法理解 C++ 中动态调度和后期绑定之间的区别。
When each one of the mechanisms is used?
什么时候使用每一种机制?
The exact quote from Wikipedia:
维基百科的确切引用:
Dynamic dispatch is different from late binding (also known as dynamic binding). In the context of selecting an operation, binding refers to the process of associating a name with an operation. Dispatching refers to choosing an implementation for the operation after you have decided which operation a name refers to. With dynamic dispatch, the name may be bound to a polymorphic operation at compile time, but the implementation not be chosen until runtime (this is how dynamic dispatch works in C++). However, late binding does imply dynamic dispatching since you cannot choose which implementation of a polymorphic operation to select until you have selected the operation that the name refers to.
动态调度不同于后期绑定(也称为动态绑定)。在选择操作的上下文中,绑定是指将名称与操作关联的过程。调度是指在您确定名称所指代的操作之后,为该操作选择一个实现。使用动态分派,名称可能在编译时绑定到多态操作,但直到运行时才选择实现(这就是 C++ 中动态分派的工作方式)。但是,后期绑定确实意味着动态调度,因为在选择名称所指的操作之前,您无法选择要选择多态操作的哪个实现。
采纳答案by WhozCraig
A fairly decent answer to this is actually incorporated into a question on late vs. early binding on programmers.stackexchange.com.
对此的一个相当体面的答案实际上已包含在程序员.stackexchange.com 上有关晚绑定与早绑定的问题中。
In short, late binding refers to the object-side of an eval, dynamic dispatch refers to the functional-side. In late binding the typeof a variable is the variant at runtime. In dynamic-dispatch, the function or subroutine being executed is the variant.
简而言之,后期绑定是指eval的对象端,动态调度是指功能端。在后期绑定中,变量的类型是运行时的变体。在动态调度中,正在执行的函数或子程序是变体。
In C++, we don't really have late binding because the type is known(not necessarily the end of the inheritance hierarchy, but at least a formal base class or interface). But we dohave dynamic dispatch via virtual methods and polymorphism.
在 C++ 中,我们没有真正的后期绑定,因为类型是已知的(不一定是继承层次结构的末尾,但至少是正式的基类或接口)。但是我们确实通过虚拟方法和多态实现了动态调度。
The best example I can offer for late-binding is the untyped "object" in Visual Basic. The runtime environment does all the late-binding heavy lifting for you.
我可以为后期绑定提供的最佳示例是 Visual Basic 中的无类型“对象”。运行时环境为您完成所有后期绑定的繁重工作。
Dim obj
- initialize object then..
obj.DoSomething()
The compiler will actually code the appropriate execution context for the runtime-engine to perform a named lookup of the method called DoSomething
, and if discovered with the properly matching parameters, actually execute the underlying call. In reality, somethingabout the type of the object is known (it inherits from IDispatch
and supports GetIDsOfNames()
, etc). but as far as the languageis concerned the typeof the variable is utterly unknown at compile time, and it has no idea if DoSomething
is even a method for whatever obj
actually isuntil runtime reaches the point of execution.
编译器实际上会为运行时引擎编写适当的执行上下文,以执行对被调用方法的命名查找DoSomething
,如果发现具有正确匹配的参数,则实际执行底层调用。实际上,有关对象类型的某些信息是已知的(它继承自IDispatch
并支持GetIDsOfNames()
等)。但是就语言而言,变量的类型在编译时是完全未知的,并且在运行时到达执行点之前,它DoSomething
甚至不知道是否是obj
实际存在的任何方法。
I won't bother dumping a C++ virtual interface et'al, as I'm confident you already know what they look like. I hope it is obvious that the C++ language simply can't do this. It is strongly-typed. It can(and does, obviously) do dynamic dispatch via the polymorphic virtual method feature.
我不会费心转储 C++ 虚拟接口等,因为我相信您已经知道它们的样子。我希望很明显 C++ 语言根本无法做到这一点。它是强类型的。它可以(并且显然确实)通过多态虚拟方法功能进行动态分派。
回答by Yochai Timmer
Late binding is calling a method by name during runtime.
You don't really have this in c++, except for importing methods from a DLL.
An example for that would be: GetProcAddress()
后期绑定是在运行时按名称调用方法。除了从 DLL 导入方法之外,您在 C++ 中并没有真正拥有它。
一个例子是:GetProcAddress()
With dynamic dispatch, the compiler has enough information to call the right implementation of the method. This is usually done by creating a virtual table.
使用动态分派,编译器有足够的信息来调用方法的正确实现。这通常是通过创建一个虚拟表来完成的。
回答by masoud
The linkitself explained the difference:
该链接本身说明了区别:
Dynamic dispatch is different from late binding (also known as dynamic binding). In the context of selecting an operation, binding refers to the process of associating a name with an operation. Dispatching refers to choosing an implementation for the operation after you have decided which operation a name refers to.
动态调度不同于后期绑定(也称为动态绑定)。在选择操作的上下文中,绑定是指将名称与操作关联的过程。调度是指在您确定名称所指代的操作之后,为该操作选择一个实现。
and
和
With dynamic dispatch, the name may be bound to a polymorphic operation at compile time, but the implementation not be chosen until runtime (this is how dynamic dispatch works in C++). However, late binding does imply dynamic dispatching since you cannot choose which implementation of a polymorphic operation to select until you have selected the operation that the name refers to.
使用动态分派,名称可能在编译时绑定到多态操作,但直到运行时才选择实现(这就是 C++ 中动态分派的工作方式)。但是,后期绑定确实意味着动态调度,因为在选择名称所指的操作之前,您无法选择要选择多态操作的哪个实现。
But they're mostly equal in C++ you can do a dynamic dispatch by virtual functions and vtables.
但是它们在 C++ 中基本相同,您可以通过虚函数和 vtable 进行动态调度。
C++ uses early binding and offers both dynamic and static dispatch. The default form of dispatch is static. To get dynamic dispatch you must declare a method as virtual.
C++ 使用早期绑定并提供动态和静态调度。调度的默认形式是静态的。要获得动态调度,您必须将方法声明为虚拟方法。
回答by bhupinder
Bindingrefers to the process of associating a name with an operation.
绑定是指将名称与操作相关联的过程。
the main thing here is function parameters these decides which function to call at runtime
这里的主要内容是函数参数,这些参数决定在运行时调用哪个函数
Dispatchingrefers to choosing an implementation for the operation after you have decided which operation a name refers to.
调度是指在您确定名称所指代的操作之后,为该操作选择一个实现。
dispatch control to that according to parameter match
根据参数匹配调度控制
http://en.wikipedia.org/wiki/Dynamic_dispatch
http://en.wikipedia.org/wiki/Dynamic_dispatch
hope this help you
希望这对你有帮助
回答by Nawaz
In C++, both are same.
在 C++ 中,两者是相同的。
In C++, there are two kinds of binding:
在 C++ 中,有两种绑定:
- static binding — which is done at compile-time.
- dynamic binding — which is done at runtime.
- 静态绑定——在编译时完成。
- 动态绑定——在运行时完成。
Dynamic binding, since it is done at runtime, is also referred to as late bindingand static binding is sometime referred to as early binding.
动态绑定,因为它是在运行时完成的,也被称为后期绑定,而静态绑定有时也被称为早期绑定。
Using dynamic-binding, C++ supports runtime-polymorphism through virtualfunctions (or function pointers), and using static-binding, all otherfunctions calls are resolved.
使用动态绑定,C++ 通过虚函数(或函数指针)支持运行时多态,并使用静态绑定,解决所有其他函数调用。
回答by Evan Langlois
Let me give you an example of the differences because they are NOT the same. Yes, dynamic dispatch lets you choose the correct method when you are referring to an object by a superclass, but that magic is very specific to that class hierarchy, and you have to do some declarations in the base class to make it work (abstract methods fill out the vtables since the index of the method in the table cant change between specific types). So, you can call methods in Tabby and Lion and Tiger all by a generic Cat pointer and even have arrays of Cats filled with Lions and Tigers and Tabbys. It knows what indexesthose methods refer to in the object's vtable at compile-time (static/early binding), even though the methodis selected at run-time (dynamic dispatch).
让我给你举一个差异的例子,因为它们不一样。是的,当您通过超类引用对象时,动态分派可以让您选择正确的方法,但是这种魔法非常特定于该类层次结构,您必须在基类中进行一些声明才能使其工作(抽象方法填写虚表,因为表中方法的索引不能在特定类型之间改变)。因此,您可以通过通用 Cat 指针调用 Tabby、Lion 和 Tiger 中的所有方法,甚至可以将 Cats 数组填充为 Lions、Tigers 和 Tabbys。它知道这些方法在编译时(静态/早期绑定)在对象的 vtable 中引用的索引,即使该方法是在运行时选择的(动态调度)。
Now, lets implement an array that contains Lions and Tigers and Bears! ((Oh My!)). Assuming we don't have a base class called Animal, in C++, you are going to have significant work to do to because the compiler isn't going to let you do any dynamic dispatch without a common base class. The indexes for the vtables need to match up, and that can't be done between unreleated classes. You'd need to have a vtable big enough to hold the virtual methods of all classes in the system. C++ programmers rarely see this as a limitation because you have been trained to think a certain way about class design. I'm not saying its better or worse.
现在,让我们实现一个包含 Lions、Tigers 和 Bears 的数组!((天啊!))。假设我们没有名为 Animal 的基类,在 C++ 中,您将有大量工作要做,因为编译器不会让您在没有公共基类的情况下执行任何动态调度。vtables 的索引需要匹配,而这不能在不相关的类之间完成。您需要有一个足够大的 vtable 来保存系统中所有类的虚拟方法。C++ 程序员很少将其视为一种限制,因为您已经被训练以某种方式思考类设计。我不是说它更好或更糟。
With late binding, the run-time takes care of this without a common base class. There is normally a hash table system used to find methods in the classes with a cache system used in the dispatcher. Where in C++, the compiler knows all the types. In a late-bound language, the objects themselves know their type (its not typeless, the objects themselves know exactly who they are in most cases). This means I can have arrays of multiple types of objects if I want (Lions and Tigers and Bears). And you can implement message forwarding and prototyping (allows behaviors to be changed per object without changing the class) and all sorts of other things in ways that are much more flexible and lead to less code overhead than in languages that don't support late binding.
使用后期绑定,运行时无需公共基类即可处理此问题。通常有一个哈希表系统用于在类中查找方法,并在调度程序中使用缓存系统。在 C++ 中,编译器知道所有类型。在后期绑定语言中,对象本身知道它们的类型(它不是无类型的,在大多数情况下,对象本身确切地知道它们是谁)。这意味着如果我愿意,我可以拥有多种类型对象的数组(Lions、Tigers 和 Bears)。并且您可以实现消息转发和原型设计(允许在不更改类的情况下更改每个对象的行为)以及其他各种方式,与不支持后期绑定的语言相比,这些方式更加灵活,代码开销更少.
Ever program in Android and use findViewById()? You almost always end up casting the result to get the right type, and casting is basically lying to the compiler and giving up all the static type-checking goodness that is supposed to make static languages superior. Of course, you could instead have findTextViewById(), findEditTextById(), and a million others so that your return types match, but that is throwing polymorphism out the window; arguably the whole basis of OOP. A late-bound language would probably let you simply index by an ID, and treat it like a hash table and not care what the type was being indexed nor returned.
曾经在 Android 中编程并使用 findViewById() 吗?您几乎总是最终将结果强制转换为正确的类型,而强制转换基本上是对编译器撒谎并放弃所有应该使静态语言变得优越的静态类型检查优点。当然,您可以改为使用 findTextViewById()、findEditTextById() 和一百万个其他方法,以便您的返回类型匹配,但这会将多态性抛诸脑后;可以说是 OOP 的整个基础。后期绑定语言可能会让您简单地按 ID 进行索引,并将其视为哈希表,而不必关心正在索引或返回的类型。
Here's another example. Let's say that you have your Lion class and its default behavior is to eat you when you see it. In C++, if you wanted to have a single "trained" lion, you need to make a new subclass. Prototyping would let you simply change the one or two methods of that particular Lion that need to be changed. It's class and type don't change. C++ can't do that. This is important since when you have a new "AfricanSpottedLion" that inherits from Lion, you can train it too. The prototyping doesn't change the class structure so it can be expanded. This is normally how these languages handle issues that normally require multiple inheritance, or perhaps multiple inheritance is how you handle a lack of prototyping.
这是另一个例子。假设你有你的 Lion 类,它的默认行为是在你看到它时吃掉你。在 C++ 中,如果你想拥有一个“训练有素的”狮子,你需要创建一个新的子类。原型设计可以让您简单地更改需要更改的特定 Lion 的一种或两种方法。它的类和类型不会改变。C++ 不能这样做。这很重要,因为当您拥有从 Lion 继承的新“AfricanSpottedLion”时,您也可以对其进行训练。原型设计不会更改类结构,因此可以对其进行扩展。这通常是这些语言处理通常需要多重继承的问题的方式,或者多重继承是您处理缺乏原型的方式。
FYI, Objective-C is C with SmallTalk's message passing added and SmallTalk is the original OOP, and both are late bound with all the features above and more. Late bound languages may be slightly slower from a micro-level standpoint, but can often allow the code to structured in a way that is more efficient at a macro-level, and it all boils down to preference.
仅供参考,Objective-C 是 C,添加了 SmallTalk 的消息传递,SmallTalk 是原始的 OOP,两者都具有上述所有功能以及更多功能。从微观层面来看,后期绑定语言可能会稍微慢一些,但通常可以让代码以一种在宏观层面更有效的方式构建,这一切都归结为偏好。
回答by 6502
Given that wordy Wikipedia definition I'd be tempted to classify dynamic dispatch as the late binding of C++
鉴于维基百科冗长的定义,我很想将动态调度归类为 C++ 的后期绑定
struct Base {
virtual void foo(); // Dynamic dispatch according to Wikipedia definition
void bar(); // Static dispatch according to Wikipedia definition
};
Late binding instead, for Wikipedia, seems to mean pointer-to-member dispatch of C++
对于维基百科来说,后期绑定似乎意味着 C++ 的指针到成员调度
(this->*mptr)();
where the selection of what is the operation being invoked (and not just which implementation) is done at runtime.
在运行时完成对正在调用的操作(而不仅仅是哪个实现)的选择。
In C++ literature however late binding
is normally used for what Wikipedia calls dynamic dispatch.
然而,在 C++ 文献中late binding
,通常用于维基百科所谓的动态调度。
回答by doptimusprime
This questionmight help you.
这个问题可能对你有帮助。
Dynamic dispatch generally refers to multiple dispatch.
动态调度一般是指多次调度。
Consider the below example. I hope it might help you.
考虑下面的例子。我希望它可以帮助你。
class Base2;
class Derived2; //Derived2 class is child of Base2
class Base1 {
public:
virtual void function1 (Base2 *);
virtual void function1 (Derived2 *);
}
class Derived1: public Base1 {
public:
//override.
virtual void function1(Base2 *);
virtual void function1(Derived2 *);
};
Consider the case of below.
考虑下面的情况。
Derived1 * d = new Derived1;
Base2 * b = new Derived2;
//Now which function1 will be called.
d->function1(b);
It will call function1
taking Base2*
not Derived2*
. This is due to lack of dynamic multiple dispatch.
它将调用function1
服用Base2*
不会Derived2*
。这是由于缺乏动态多重分派。
Late binding is one of the mechanism to implement dynamic single dispatch.
后期绑定是实现动态单分派的机制之一。
回答by Tristan Brindle
Dynamic dispatch is what happens when you use the virtual
keyword in C++. So for example:
virtual
在 C++ 中使用关键字时会发生动态调度。例如:
struct Base
{
virtual int method1() { return 1; }
virtual int method2() { return 2; } // not overridden
};
struct Derived : public Base
{
virtual int method1() { return 3; }
}
int main()
{
Base* b = new Derived;
std::cout << b->method1() << std::endl;
}
will print 3
, because the method has been dynamically dispatched. The C++ standard is very careful notto specify how exactly this happens behind the scenes, but every compiler under the sun does it in the same way. They create a table of function pointers for each polymorphic type (called the virtual tableor vtable), and when you call a virtual method, the "real" method is looked up from the vtable, and that version is called. So you can imaging something like this pseudocode:
将打印3
,因为该方法已被动态调度。C++ 标准非常小心,没有具体说明这在幕后究竟是如何发生的,但阳光下的每个编译器都以相同的方式做到这一点。它们为每个多态类型(称为虚表或vtable)创建一个函数指针表,当您调用虚方法时,会从 vtable 中查找“真实”方法,并调用该版本。所以你可以成像这样的伪代码:
struct BaseVTable
{
int (*_method1) () = &Base::method1; // real function address
int (*_method2) () = &Base::method2;
};
struct DerivedVTable
{
int (*method) () = &Derived::method1;
int (*method2) () = &Base::method2; // not overridden
};
In this way, the compiler can be sure that a method with a particular signature exists at compile time. However, at run-time, the call might actually be dispatched via the vtable to a different function. Calls to virtual functions are a tiny bit slower than non-virtual calls, because of the extra indirection step.
通过这种方式,编译器可以确保在编译时存在具有特定签名的方法。但是,在运行时,调用实际上可能通过 vtable 分派到不同的函数。由于额外的间接步骤,对虚拟函数的调用比非虚拟调用慢一点。
On the other hand, my understanding of the term late bindingis that the function pointer is looked up by nameat runtime, from a hash table or something similar. This is the way things are done in Python, JavaScript and (if memory serves) Objective-C. This makes it possible to add new methods to a class at run-time, which cannot directly be done in C++. This is particularly useful for implementing things like mixins. However, the downside is that the run-time lookup is generally considerably slower than even a virtual call in C++, and the compiler is not able to perform any compile-time type checking for the newly-added methods.
另一方面,我对后期绑定一词的理解是,函数指针是在运行时按名称从哈希表或类似的东西中查找的。这就是在 Python、JavaScript 和(如果没记错的话)Objective-C 中处理事情的方式。这使得在运行时向类添加新方法成为可能,而这在 C++ 中无法直接完成。这对于实现诸如 mixin 之类的东西特别有用。但是,缺点是运行时查找通常比 C++ 中的虚拟调用慢得多,并且编译器无法对新添加的方法执行任何编译时类型检查。
回答by jester
In C++, both dynamic dispatch
and late binding
is the same. Basically, the value of a single object determines the piece of code invoked at runtime. In languages like C++ and java dynamic dispatch is more specifically dynamic single dispatch which works as mentioned above. In this case, since the binding occurs at runtime, it is also called late binding
. Languages like smalltalk allow dynamic multiple dispatch in which the runtime method is chosen at runtime based on the identities or values of more than one object.
在 C++ 中,dynamic dispatch
和late binding
是相同的。基本上,单个对象的值决定了在运行时调用的代码段。在 C++ 和 java 等语言中,动态调度更具体地说是动态单调度,其工作方式如上所述。在这种情况下,由于绑定发生在运行时,因此也称为late binding
。像 smalltalk 这样的语言允许动态多重分派,其中在运行时根据多个对象的身份或值选择运行时方法。
In C++ we dont really have late binding, because the type information is known. Thus in the C++ or Java context, dynamic dispatch and late binding are the same. Actual/fully late binding, I think is in languages like python which is a method-based lookup rather than type based.
在 C++ 中,我们真的没有后期绑定,因为类型信息是已知的。因此,在 C++ 或 Java 上下文中,动态分派和后期绑定是相同的。实际/完全后期绑定,我认为是在像 python 这样的语言中,它是基于方法的查找而不是基于类型的。