答案 0 :(得分:8)
静态与动态绑定是关于 当 运行的确切代码(即函数的地址)已知:在compile-,link-(两者都是“静态”) ,加载或运行时(均为“动态”)。
多态性首先是关于 如何 运行的确切代码已知:要符合多态性,必须从 类型 正在处理的数据。当直到运行时才知道“动态类型”数据(通常是因为类型由运行时数据输入确定),必须使用动态绑定,这需要动态多态(也就是运行时多态性; C ++提供虚拟调度)这个类别的机制)。还有其他情况,即使正在处理的数据类型在编译时可用,虚拟分派也很有用 - 特别是在代码更改后最小化/消除(重新)编译时间,以及调整代码“膨胀”。无论如何,编译时静态多态性使用编译时类型的已知类型在编译或链接时绑定(即“静态”)。
struct Base { virtual void f(); void g(); };
struct Derived : Base { void f(); void g(); };
Derived d;
d.f(); // if definition's in a shared library, needs dynamic binding
// otherwise (same translation unit, linked object, static lib)
// compiler should optimise to static binding
// (though functionally either would work)
Base* p = factory(data);
p->f(); // dynamic binding - if p points to a Base, use Base::f()
// - if p pointer to a Derived, use Derived::f()
void some_func(const char*); // note: no polymorphism / overloads
some_func("hello world\n");
// if some_func is defined in...
// - shared / dynamic link library, binds dynamically
// - otherwise, static binding
std::cout << "hello world\n"; // static binding
// compile-time polymorphism from (operator) overloading
绑定通常是指程序将函数调用解析为特定函数实现的机器代码的时间:
静态 表示在编译期间会发生这种情况
动态 表示在可执行程序启动/运行时会发生这种情况
“绑定” - 和“currying” - 也用于描述仿函数参数的规定(在Stroustrup's C++11 FAQ中搜索“绑定”)
C ++程序动态绑定函数调用的唯一情况是:
当使用动态库时,在这种情况下,绑定可以在调用main()
之前由操作系统加载程序完成,或者在使用dlsym
(或类似操作系统)的代码中显式完成特定函数),它返回一个函数指针,用于调用动态库中的函数(.so,.dll,...)。
在虚拟分派中,当在运行时找到虚拟成员函数时,通常通过跟随从数据对象到虚拟分派表的指针来记录函数指针
当程序员明确使用函数指针时
在其他情况下,绑定是静态的:编译器本身将jmp或调用写入特定的内存地址/偏移量(无论是绝对的还是相对于程序计数器无关紧要)到它创建的对象或可执行文件中,并且在程序加载或执行期间不会被修改。
静态/动态绑定分类只与多态性有一点重叠:
虚拟调度通常使用动态绑定(但有时可以根据上面的示例进行优化)和
C ++中所有其他形式的多态(即重载,模板,内联宏扩展)都使用静态绑定,但
大多数非多态代码也是如此:对于不在共享/动态库中的函数的任何“正常”非虚拟调用也会在编译时解析。
答案 1 :(得分:4)
多态性是指对象对同一消息的行为不同的能力。
多态性有两种类型。静态或动态。在动态多态中,对消息的响应是在运行时决定的,而在静态多态中,它是在编译时决定的。
动态多态中的数据类型分配称为延迟或动态绑定。在动态绑定方法中,调用基于运行时的对象(实例)类型进行。例如:方法覆盖
如果数据类型的分配在编译时,则称为早期或静态绑定。在静态绑定方法中,调用在编译时基于引用类型发生。例如:方法重载
方法重载 - 这意味着创建一个具有相同名称和不同签名的新方法。它使用早期绑定。
方法重写 - 这是为其子类中的现有方法提供新定义的过程。所有对象都是在堆上运行时创建的,因此实际绑定仅在运行时完成。
答案 2 :(得分:2)
重要区别在于发生错误时显示错误。如果您有静态绑定,则可以在编译时捕获错误。运行时错误很难找到。
答案 3 :(得分:1)
不同之处在于,首先是技术(绑定),第二个是基于此技术可以使用的特征(多态)。
多态性意味着编写通用代码以使用不同的对象而不知道它们的确切类型。
静态绑定是一种语言属性,允许编译器解析在编译时调用的类型。但是可以存在没有多态性的静态绑定。
动态绑定是一种语言属性,允许在运行时决定类型。但是可以存在没有多态性的动态绑定。如果动态绑定用于编写与层次结构中几个类的对象一起工作的通用代码,那么它将是动态多态。
答案 4 :(得分:1)
编译时多态是相当模糊和矛盾的。多态性用于在运行时基于对象类型调用特定方法。它与后期绑定又称动态绑定密切相关。您可以使用virtual
关键字来实现这一目标:
class Base
{
virtual void do() // Note the virtual
{
cout << "Base" << endl;
}
};
class Derived : public Base
{
virtual void do()
{
cout << "Derived" << endl;
}
};
void use(Base& b)
{
b.do(); // There you have late binding with 'virtual'
// If you remove 'virtual', you have early binding,
// Base::do() will be called everytime
}
Base b;
Derived d;
use(b); // print Base
use(d); // print Derived, but print Base if you do not use virtual in Base.
函数重载只是语法糖,与多态无关。你可以用它来写:
void use(int);
void use(MyClass&);
void use(const std::string&);
而不是:
void useInteger(int);
void useMyClass(MyClass&);
void useString(const std::string&);
正如您可以将它与方法一起使用,您可以相信它与多态性有关。要注意它与多态性不能很好地混合!
关于静态多态性,该术语有时用于描述在编译时模仿多态的模板使用的模式:请参阅CRTP or Curriously Reccuring Template Pattern