静态与动态绑定是关于何时运行的确切代码(即函数的地址)已知:在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
Run Code Online (Sandbox Code Playgroud)
绑定通常是指程序将函数调用解析为特定函数实现的机器代码的时间:
static表示在编译期间发生这种情况
动态意味着在可执行程序启动/运行时会发生这种情况
"绑定" - 和"currying" - 也用于描述仿函数参数的规定(在Stroustrup的C++ 11 FAQ中搜索"绑定" )
C++程序动态绑定函数调用的唯一情况是:
当使用动态库时,在这种情况下,绑定可以在main()调用之前由操作系统加载器完成,或者在代码中使用dlsym(或类似的特定于OS的函数)显式地完成,该函数返回用于调用找到的函数的函数指针在动态库中(.so,.dll,...).
在虚拟分派中,当在运行时找到虚拟成员函数时,通常通过跟随从数据对象到虚拟分派表的指针,其中记录了函数指针
当程序员明确使用函数指针时
在其他情况下,绑定是静态的:编译器本身将jmp或调用写入特定的内存地址/偏移量(无论是绝对的还是相对于程序计数器无关紧要)到它创建的对象或可执行文件中,并且不会被修改在程序加载或执行期间.
静态/动态绑定分类只与多态性有一点重叠:
虚拟调度通常使用动态绑定(但有时可以根据上面的示例进行优化)和
C++中所有其他形式的多态(即重载,模板,内联宏扩展)都使用静态绑定,但是
大多数非多态代码也是如此:对于不在共享/动态库中的函数的任何"正常"非虚拟调用也会在编译时解析.
| 归档时间: |
|
| 查看次数: |
15883 次 |
| 最近记录: |