c ++ 11 — Что является противоположностью спецификатору c ++ `override` /` final`?

  • В C ++ 11 override спецификатор защищает от переопределения предполагаемой виртуальной базовой функции (поскольку сигнатуры не совпадают).
  • final спецификатор защищает от непреднамеренного переопределения функции в производном классе.

=> Есть ли спецификатор (что-то вроде может быть first или же no_override) что защищает от переопределения неизвестной базовой функции?

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


РЕДАКТИРОВАТЬ 4: Чтобы этот вопрос был простым, а ответы — актуальными,

оригинальный псевдокод

  • Аннотация class B : A имеет private: virtual void fooHasBeenDone() = 0;
  • class C : B инвентарь private: virtual void fooHasBeenDone() override { react(); }
  • Сейчас class A получает новый private: virtual void fooHasBeenDone();
  • Но новый A::foo может быть что-то другое, чем оригинал B::foo,

и конкретный пример

  • Аннотация class B : A имеет virtual void showPath() = 0; По пути PainterPath
  • class C : B инвентарь virtual void showPath() override { mPath.setVisible(); }
  • Сейчас class A получает новый virtual void showPath(); имеется в виду путь к файлу
  • Теперь, когда A вызывает showPath (), B показывает painterPath вместо некоторого пути к файлу.

Конечно, это неправильно, и я должен переименовать B::showPath() в B::showPainterPath() и реализовать B::showPath() override также. Я просто хотел бы получить информацию от компилятора.


Вот компиляция пример из реальной жизни:

#include <iostream>
#define A_WITH_SHOWPATH

class A
{
#ifdef A_WITH_SHOWPATH
public:
void setPath(std::string const &filepath) {
std::cout << "File path set to '" << filepath << "'. Display it:\n";
showPath();
}
// to be called from outside, supposed to display file path
virtual void showPath() {
std::cout << "Displaying not implemented.\n";
}
#else
// has no showPath() function
#endif
};

class B : public A
{
public:
virtual void showPath() = 0; // to be called from outside
};

class C1 : public B {
public:
virtual void showPath() override {
std::cout << "C1 showing painter path as graphic\n";
}
};

class C2 : public B {
public:
virtual void showPath() override {
std::cout << "C2 showing painter path as widget\n";
}
};int main() {
B* b1 = new C1();
B* b2 = new C2();

std::cout << "Should say 'C1 showing painter path as graphic':\n";
b1->showPath();
std::cout << "---------------------------\n";
std::cout << "Should say 'C2 showing painter path as widget':\n";
b2->showPath();
std::cout << "---------------------------\n";

#ifdef A_WITH_SHOWPATH
std::cout << "Should give compiler warning\n or say \"File path set to 'Test'. Display it:\"\n and \"Displaying not implemented.\",\n but not \"C1 showing painter path as graphic\":\n";
b1->setPath("Test");
std::cout << "# Calling setPath(\"Test\") on a B pointer now also displays the\n#  PainterPath, which is not the intended behavior.\n";
std::cout << "# The setPath() function in B should be marked to never override\n#  any function from the base class.\n";
std::cout << "---------------------------\n";
#endif
return 0;
}

Запустите его и посмотрите на вывод текста.


Для справки, более старый пример с конкретным вариантом использования (экземпляр PainterPath):

https://ideone.com/6q0cPD (ссылка может быть просрочена)

8

Решение

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

Нужно добавить любой новый метод в базовый класс с помощью final спецификатор. Это поможет получить ошибку компилятора для любых совпадающих сигнатур. Потому что это сделает последующие производные сигнатуры метода класса автоматически «первыми» в своем роде. Позже final ключевое слово может быть удалено, как это было предназначено только для «проверки из первых рук».

Ввод & удаление final Ключевое слово после вновь добавленного базового метода аналогично тому, как компилировать двоичный файл с помощью debug (g++ -g) вариант, который поможет вам исправить ошибку. В производстве эта опция отладки удалена для оптимизации.

Из вашего примера:

class A {};  // no method, no worry

class B {
public: virtual void showPath() = 0;  // ok
};
...

Теперь вы случайно добавляете подобный метод в A, что приводит к ошибке:

class A {
public: virtual void showPath() final;  // same signature by chance
// remove the `final` specifier once the signature is negotiated
};
class B {
public: virtual void showPath() = 0;  // ERROR
};

Так что подписи между новыми A::showPath() & существующий B::showPath() должны быть предметом переговоров & затем продолжить, удалив final спецификатор.

2

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

Нет там нет.

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

(Конечно, вы можете отметить вашу новую функцию final просто для того, чтобы проверить, что функция дочернего класса не собирается засорять ее.)

Ваш единственный вариант — прибегнуть к инструментам анализа кода.

(Обратите внимание, что VS2012 не реализует и даже не претендует на реализацию стандарта C ++ 11, хотя и имеет некоторые из них.)

2

Этот ответ является вики сообщества, потому что он объединяет все остальные ответы. Пожалуйста, подтвердите конкретный ответ, который был полезен для вас, а также этот.

  1. Нет, спецификатора нет first или же no_override, (ответ)
  2. Вы должны использовать override Спецификатор как можно чаще.
    Qt имеет макрос Q_DECL_OVERRIDE что расширяется до override, если доступно.
    Если не доступно, по крайней мере пометьте каждую переопределяющую функцию комментарием.
  3. Если вы это сделаете, есть флаги компилятора, которые предупреждают об отсутствии override:
    «Clang теперь имеет -Winconsistent-missing-overrideи более новые GCC имеют -Wsuggest-override,«
    Я не знаю флаг VS2012 для этого. Не стесняйтесь редактировать.
  4. Вы можете имитировать желаемое поведение, добавив «секрет», который базовый класс не может знать. (ответ)
    Это полезно в очень специфических случаях использования, но в целом нарушает концепцию виртуальности (см. Комментарии к другим ответам).
  5. Если у вас нет базового класса и возник конфликт (например, предупреждение компилятора), вам нужно будет переименовать вашу виртуальную функцию во всех производных классах.
  6. Если у вас есть базовый класс, вы можете временно добавить final к любой новой виртуальной функции. (ответ)
    После того, как код скомпилирован без ошибок, вы знаете, что никакой функции с таким именем и сигнатурой не существует ни в одном производном классе, и вы можете удалить final снова.

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

2

C ++, кажется, не предоставляет такие средства из коробки. Но вы можете имитировать это следующим образом:

template<class Base>
class Derived : public Base
{
private:
struct DontOverride {};

public:
// This function will never override a function from Base
void foo(DontOverride dummy = DontOverride())
{
}
};

Если вы намерены ввести новый виртуальная функция, затем сделайте это, как показано ниже:

template<class Base>
class Derived : public Base
{
protected:
struct NewVirtualFunction {};

public:
// This function will never override a function from Base
// but can be overriden by subclasses of Derived
virtual void foo(NewVirtualFunction dummy = NewVirtualFunction())
{
}
};
1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector