Что мне нужно сделать, чтобы увидеть статическое и динамическое связывание в действии? [C ++]

Я использую GCC на Linux.

Я хочу понять рабочие Виртуальные функции.

Какой код C ++ я должен написать, чтобы увидеть и понять, как именно статическое и динамическое связывание происходит с и без Виртуальных функций?

И как «увидеть», как они были окончательно связаны и что именно произошло во время процесса?

1

Решение

Вот пример. Вы можете создать и запустить этот код с функцией, установленной как виртуальная функция или нет. Чтобы получить виртуальное поведение, динамическую диспетчеризацию, динамическое связывание, создайте его с помощью макроса препроцессора. IS_VIRTUAL определены. Чтобы увидеть статическое связывание, создайте его без определения этого макроса.

#include <iostream>

#if defined(IS_VIRTUAL)
#define CONDITIONAL_VIRTUAL virtual
#else
#define CONDITIONAL_VIRTUAL
#endif

struct A {
CONDITIONAL_VIRTUAL void foo() { std::cout << "A\n"; }
};

struct B : A {
CONDITIONAL_VIRTUAL void foo() { std::cout << "B\n"; }
};

// global objects
A a; B b;

enum object_type { get_A, get_B };
A *get_object(object_type t) {
switch (t) {
case get_A: return &a;
case get_B: return &b;
}
}

int main() {
std::cout << "Choose A or B: ";
char c;
std::cin >> c;

A *x = get_object( c == 'A' ? get_A : get_B );
x->foo();
}

Привязка имеет отношение к оценке x->foo(), Компилятор должен выяснить, какой код выполнять для этого выражения. При статическом и динамическом связывании компилятор x и видит его тип A*так это выглядит на struct A и ищет foo() декларация.

При статической привязке компилятор находит, что foo() не является virtualтак что компилятор просто идет вперед и генерирует код, который вызывает foo() метод. Просто.

При динамическом связывании компилятор видит этот метод как virtualи поэтому компилятор вместо этого генерирует код, который во время выполнения будет использовать таблицу указателей функций, связанных с объектом x выбрать метод для вызова, а затем вызвать любой метод найден. Компилятор также генерирует код в другом месте для создания таблиц для глобального a а также b объекты. Для глобального a возражает, что таблица указывает на A::foo()и для глобального b это заставляет таблицу указывать на B::foo(), Так что если x указывает на b объект, то поиск таблицы приведет к B::foo() и это функция, которая будет вызвана.

В общем, компилятор должен убедиться, что все объекты, которые имеют виртуальные методы, также имеют таблицу с ними, которая указывает на нужные функции для вызова, так что каждый раз, когда виртуальный вызов выполняется для объекта, программа может во время выполнения получить таблицу, связанную с объектом, и найдите правильный метод для вызова.

Так что соберите вышеупомянутую программу как в статическом, так и в динамическом режимах, а затем запустите ее и посмотрите результат, который вы получаете для каждого входа. Заполните таблицу ниже данными, которые вы получаете для каждой комбинации ввода и типа привязки.

       Binding |   static     dynamic
Input
-----
A                    ?           ?
B                    ?           ?

Во всех случаях выход производится путем оценки того же x->foo() вызов метода. В каких случаях динамическое связывание доказательств? Соответствует ли это вашему пониманию приведенного выше объяснения динамического связывания?

1

Другие решения

class Base {
public:
int Foo();
virtual int Bar();
};

class D1 : public Base {
public:
int Foo();
virtual int Bar();
};

class D2 : public Base {
public:
int Foo();
virtual int Bar();
};

main()
{
Base * b = (rand() < 100) ? new D1 : new D2;
// Always calls Base::Foo()
b->Foo();
// Call either D1::Bar() or D2::Bar()
b->Bar();
}
-1

По вопросам рекламы [email protected]