Каковы преимущества позднего связывания? Приведите один пример в контексте указателей на функции в C++

Во-первых, позвольте мне уточнить, этот вопрос не объясняет мои сомнения ясно. Чтобы установить контекст ясно. Я задаю этот вопрос специально в отношении указателей на функции в 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;

Может ли кто-нибудь объяснить на простом примере, подобном приведенному ниже, где позднее связывание выгодно и почему кто-то должен выбирать его вместо раннего связывания?

1 ответ

Решение

Хорошо, я собираюсь пропустить весь вопрос определения "раннее связывание против позднего связывания" и делать вид, что вы спросили: "Почему кто-то использует указатели на функции вместо оператора switch?"

Потому что указатели на функции более гибкие. Они не статичны. Давайте возьмем бизнес конец вашего кода:

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);
    }
}

Это красиво и функционально. Но это не гибкий. Зачем? Потому что все функции, которые могут быть вызваны, определяются InvokeOperation; если вы хотите добавить новую операцию, вы должны иметь возможность изменить 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 были частью какой-то библиотеки, у вас не было бы права менять ее. Со статическим связыванием у вас будет негибкая система; то, что он поддерживает, это то, что он всегда будет поддерживать.

С помощью динамического связывания вы можете добавлять все, что захотите, независимо от того, имеете ли вы право изменять библиотеку напрямую или нет.

Другие вопросы по тегам