Беда с разными видами полиморфизма

Из того, что я узнал до сих пор, есть два вида полиморфизма: время компиляции и время выполнения. Во время компиляции полиморфная функция или оператор разрешается компилятором, а во время выполнения - во время выполнения. Примеры полиморфизма времени компиляции включают перегрузку функций и операторов, а полиморфизм времени выполнения включает переопределение функций и виртуальные функции. Кроме того, есть такие случаи, как Раннее связывание и Позднее связывание, о которых я расскажу позже. Рассмотрим следующий код:

class base {
public:
    void Print() {
        std::cout << "This is parent class\n";
    }
};

class derived : public base {
public:
    void Print() {
        std::cout << "This is derived class\n";
    }
};

Если я сделаю это:

base b1;
b1.Print();
derived d1;
d1.Print();

результат довольно очевиден:

This is parent class
This is derived class

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

base b1;
derived d1;
base* pb = &b1;
base* pb2 = &d1;
pb->Print();
pb2->Print();

Выход будет:

This is parent class
This is parent class

Это связано с ранним связыванием, компилятор проверяет тип объекта, вызывающего функцию, а не тип объекта, который ее обрабатывает. И, очевидно, это делается во время компиляции. Теперь, если я использую virtual Ключевое слово в определении функции базового класса, то я могу легко сделать вышеупомянутое без каких-либо хлопот, что связано с поздним связыванием, которое сохраняет определение функции для времени выполнения на основе типа объекта, который ее обрабатывает. Это пример полиморфизма во время выполнения.

Извините, что занял слишком много времени, мой вопрос: разве это единственный способ достичь полиморфизма во время выполнения? Кроме того, если переопределение функции является полиморфизмом во время выполнения, то предыдущий пример (то есть, тот, что с Ранним связыванием) также должен быть полиморфизмом во время выполнения, так как он также выполняет переопределение функции.

1 ответ

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

void foo(Base * _b)
{
   if(_b->typeID == TID_BASE)
   {
       b->bar();
   }
   else if(_b->typeID == TID_DERIVED)
   {
       static_cast<Derived*>(_b)->bar();
   }
}

Где идентификатор типа - это некоторая форма перечисления или указатель, который однозначно идентифицирует тип. Тем не менее, я бы никогда не рекомендовал делать это, если вы на самом деле не измерили, что это влияет на производительность в вашем случае.

По поводу вашего последнего вопроса. Нет, это ни в коем случае не является поздним связыванием, потому что вы вообще не отменяете никаких функций. В вашем примере есть один Print функция в Base класс и один в Derived учебный класс. Приведя ваш объект к BaseВы явно запрашиваете Base учебный класс Print функция.

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