后期绑定的优点是什么?举一个C++中函数指针上下文的例子

What are the advantages of late binding? Give one example in context of function pointers in C++

本文关键字:C++ 一个 函数 指针 上下文 绑定 是什么      更新时间:2023-10-16

首先,让我澄清一下这个问题并不能清楚地解释我的疑虑。清除上下文。我是专门针对C/C++中的函数指针提出这个问题的。

我知道早期绑定和后期绑定的区别以及它的工作原理。我想了解的是以下一个在C/C++中使用函数指针的例子:

在许多教科书中都提到:

后期绑定的优点是它比早期更灵活绑定,因为不需要决定调用什么函数直到运行时。

此外,它还提到:

对于后期绑定,程序必须读取指针,然后跳转到该地址。这涉及一个额外的步骤,使其稍微变慢。

#include <iostream>
using namespace std;
int Add(int nX, int nY)
{
    return nX + nY;
}
int Subtract(int nX, int nY)
{
    return nX - nY;
}
int Multiply(int nX, int nY)
{
    return nX * nY;
}
int main()
{
    int nX;
    cout << "Enter a number: ";
    cin >> nX;
    int nY;
    cout << "Enter another number: ";
    cin >> nY;
    int nOperation;
    do
    {
        cout << "Enter an operation (0=add, 1=subtract, 2=multiply): ";
        cin >> nOperation;
    } while (nOperation < 0 || nOperation > 2);
    // Create a function pointer named pFcn (yes, the syntax is ugly)
    int (*pFcn)(int, int);
    // Set pFcn to point to the function the user chose
    switch (nOperation)
    {
        case 0: pFcn = Add; break;
        case 1: pFcn = Subtract; break;
        case 2: pFcn = Multiply; break;
    }
    // Call the function that pFcn is pointing to with nX and nY as parameters
    cout << "The answer is: " << pFcn(nX, nY) << endl;
    return 0;
}

在这里,使用后期绑定没有优势,而应该优先使用以下示例中的早期绑定。

int nResult = 0;
switch (nOperation)
{
    case 0: nResult = Add(nX, nY); break;
    case 1: nResult = Subtract(nX, nY); break;
    case 2: nResult = Multiply(nX, nY); break;
}
cout << "The answer is: " << nResult << endl;

有人能用下面这样一个简单的例子解释一下后期绑定的优势吗?为什么有人应该选择它而不是早期绑定?

好吧,我将跳过整个"早期绑定与后期绑定"的定义问题,假装你问"为什么有人会使用函数指针而不是开关语句?">

因为函数指针更灵活。它们不是静态的让我们来看看你的代码的商业端:

int InvokeOperation(int nOperation, int nX, int nY)
{
    switch (nOperation)
    {
        case 0: return Add(nX, nY);
        case 1: return Subtract(nX, nY);
        case 2: return Multiply(nX, nY);
    }
}

这很好,很实用。但它不是灵活。为什么?因为所有可以调用的函数都是由CCD_ 1定义的;如果要添加新操作,则必须能够更改InvokeOperation

相比之下,如果使用函数指针,则可以构建一个完整的操作注册表:

using Func = int(*)(int, int);
struct Op{Func func; std::string name;};
std::vector<Func> funcs =
{
    {&Add, "Add"},
    {&Subtract, "Subtract"},
    {&Multiply, "Multiply"},
};
int InvokeOperation(int nOperation, int nX, int nY)
{
    return funcs[nOperation].func(nX, nY);
}

现在,如果您想添加更多的操作,只需在funcs中插入元素即可。如果InvokeOperation是某个库的一部分,你就不一定有权更改它。使用静态绑定,你会有一个不灵活的系统;它支持的是它将始终支持的内容。

使用动态绑定,无论您是否有权直接修改库,都可以添加任何您想要的内容。