C ++ перегрузка и переопределение времени разрешения - PullRequest
2 голосов
/ 29 марта 2012

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

Ответы [ 4 ]

3 голосов
/ 29 марта 2012

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

Предполагая, что вы говорите о полиморфизме, т.е.

#include <iostream>

class Base
{
public:
    virtual void Foo()
    {
        std::cout << "Base::Foo()" << std::endl;
    }
};

class Derived : public Base
{
public:
    virtual void Foo()
    {
        std::cout << "Derived::Foo()" << std::endl;
    }
};

Приведенный выше код позволяет примерно так работать, как ожидалось:

void CallFoo(Base& b)
{
    b.Foo(); 
}

int main()
{
    Base b;
    Derived d;
    CallFoo(b); // calls Base::Foo()
    CallFoo(d); // Calls Derived::Foo();
}

Важно понимать, что CallFoo() ничего не знает о том, что на самом деле b (это может относиться к экземпляру Base или Derived). Все, что получает CallFoo() - это ссылка на Base, которая ничего не говорит о том, к чему он на самом деле относится, поэтому компилятор не может сказать, что это, когда компилирует CallFoo(). Следовательно, определение того, следует ли вызывать Base::Foo() или Derived::Foo(), обязательно является решением времени выполнения.

Удаление ключевых слов virtual (чтобы отключить переопределение) приведет к тому, что приведенный выше код будет печатать дважды Base::Foo(), а не Base::Foo(), а затем Derived::Foo(). Это связано с тем, что без ключевого слова virtual компилятор просто разрешит вызов Base::Foo() во время компиляции.

При этом, поскольку виртуальные функции несут некоторые издержки (в конце концов, правильная функция, которую нужно вызвать, является решением времени выполнения), компиляторы постараются изо всех сил выяснить фактический тип b в CallFoo() если может. В этом случае это становится решением во время компиляции. Это, однако, деталь реализации.

2 голосов
/ 29 марта 2012

почему переопределение разрешается во время выполнения, тогда как перегрузка разрешается во время компиляции?

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

В случае перегрузки фактическая функция, которую необходимо вызвать, может быть определена компиляторами на основе только параметров, передаваемых в функцию, поэтому компилятору не нужно ждать времени выполнения для разрешения таких вызовов, поскольку все типы параметров известны во время компиляции, поскольку C ++ является статически типизированным языком, все типы должны быть известны во время компиляции.

2 голосов
/ 29 марта 2012

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

0 голосов
/ 29 марта 2012

Перегрузка функций в C ++ может быть обработана самим компилятором. Во время перегрузки функции компилятор «декорирует» имена функций, технически называемые name mangling. Таким образом, в сгенерированном коде каждый перегруженный метод будет иметь отдельное имя. Таким образом, компилятор знает, какой метод вызывать во время компиляции.

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

...