Страницы

Поиск по вопросам

понедельник, 25 ноября 2019 г.

virtual и override


Просматривая различные примеры (один из них: Лекция. Виртуальные функции и полиморфизм)
увидел, что при использовании virtual можно переопределять метод производного класса. Также увидел, что даже если ссылаться на исходный класс — все равно будет вызван метод, переопределенный в дочернем классе, только если не указана область видимости метода. 

Но (!) Я копаю кучу исходников С++ и вижу, что когда переопределяют метод в дочерне
классе, то добавляют слово override. Однако в вышепоказанном примере никто override не пишет. 

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

Помогите разобраться поконкретнее , virtual и override в С++ используются всегд
только в паре или не всегда? И если не всегда в паре, то как это вообще влияет на выполнение кода?

Я просто пишу код и у меня выбивает ошибка на чтение нулевого адреса. Я думаю что что-то напортачил с этими виртуальными методами, хотя делаю все по шаблону.
    


Ответы

Ответ 1



virtual используется в базовом классе, чтобы сделать функцию виртуальной (полиморфной). struct A { void f(); // обычная функция }; struct B : A { virtual void f(); // виртуальная функция (перекрывает обычную A::f) virtual void g() = 0; // чисто-виртуальная функция }; Также virtual можно, но не обязательно использовать в классах-потомках struct C1 : B { void f(); // виртуальная, т.к. B::f виртуальная void g() = 0; // все еще чисто-виртуальная функция }; struct C2 : B { virtual void f(); // виртуальная, т.к. B::f виртуальная virtual void g() = 0; // все еще чисто-виртуальная функция }; override используется в классе-потомке, чтобы указать что функция должна переопределят виртуальную функцию, объявленную в базовом классе. Это позволяет избавиться от ошибок, когда из-за опечатки вместо переопределения существующей виртуальной функции была создана новая (с другим именем или сигнатурой). struct C3 : B { void f() override; // гарантированное переопределение B::f void g() override = 0; }; Допускается, но не рекомендуется использование virtual совместно с override. struct C4 : B { // virtual не имеет смысла, т.к. override подразумевает virtual. virtual void f() override; }; Кроме override существует спецификатор final, который запрещает переопределение виртуальной функции в классах-потомках. struct C5 : B { virtual void f() final; };

Ответ 2



override как бы говорит компилятору - ищи эту функцию в классах предках выше, он виртуальна. (не найдет - выдаст ошибку) Без этого слова компилятор не найдя функцию у предков определит ее как новую функцию и ошибки не будет

Ответ 3



Когда мы объявляем функцию виртуальной, используя virtual, то это равносильно тому, как если бы мы обращались к ней не напрямую, а через указатель. typedef void (*functionPointer)(ClassA*); struct ClassA { functionPointer func1; bool called; }; void callMe(ClassA* thisA) { thisA->called = true; } ClassA ca; ca.called = false; ca.func1 = callMe; ca.func1(&ca); // Будет вызвана функция callMe(). Поэтому при обращении к перекрытому методу всегда будет вызвана именно "последняя" версия функции. Даже если обращаться к ней, указывая класс-предок. C помощью override можно избежать случайного поведения наследования в коде.В следующе примере показано, в какой ситуации без использования override поведение функции-члена производного класса может быть случайным. Компилятор не выдает ошибки при использовании этого кода. class BaseClass { virtual void funcA(); virtual void funcB() const; virtual void funcC(int = 0); void funcD(); }; class DerivedClass: public BaseClass { virtual void funcA(); // ok, работает как подразумевается virtual void funcB(); // DerivedClass::funcB() не const, так что он не перекрывает // BaseClass::funcB() const и является новым методом virtual void funcC(double = 0.0); // DerivedClass::funcC(double) имеет другой // тип параметра, чем BaseClass::funcC(int), так что // DerivedClass::funcC(double) тоже новый метод }; Подробнее можно прочитать здесь.

Ответ 4



virtual и override — ключевые слова, используются для занесения методов в таблиц виртуальных методов (координирующую таблицу). Это такой механизм, используемый в языках программирования для поддержки динамического соответствия. Обычно компилятор создает отдельную vtable для каждого класса. После создания объект указатель на эту vtable, называемый виртуальный табличный указатель или vpointer, добавляетс как скрытый член данного объекта (а зачастую как первый член). Компилятор также генерирует «скрытый» код в конструкторе каждого класса для инициализации vpointer-ов его объектов адресами соответствующей vtable. Координирующая таблица объекта содержит адреса динамически связанных методов объекта. Метод вызывается при выборке адреса метода из таблицы.

Ответ 5



Возможность override появилась в С++ начиная с С++11. Ваши лекции и примеры в ни были скорее всего изначально составлены еще до того времени и с тех пор не обновлялись. Как вы сами [теперь] понимаете, override - это лишь средство самоконтроля, использовани override является необязательным, т.е. работоспособность более раннего кода появлением override никак не нарушается.

Комментариев нет:

Отправить комментарий