С++ запрещает перезаписывать виртуальную функцию

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

class A {
    public:
        virtual void func1()=0;
        virtual void func2()=0;
        ...
}
class B: public A {
    public:
        virtual void func1() {...}
}

Поэтому, если кто-то создаст класс C, производный от B, ему придется реализовать func2:

class C: public B {
    public:
        virtual void func2() {...}
}

Для моего приложения очень важно, чтобы класс C не перезаписывал func1, исключая B::func1().

Есть ли способ запретить перезапись этой виртуальной функции для всех дочерних классов B? Если не в простом С++, есть ли что-то в boost MPL, которое вызывает ошибку компилятора, когда эта функция перезаписывается?


person Heinzi    schedule 24.08.2011    source источник
comment
Есть ли когда-нибудь случай, когда подкласс A должен переопределять func2, а если нет, то почему он виртуальный?   -  person SingleNegationElimination    schedule 24.08.2011
comment
Не думайте, что это возможно. Поскольку при new C создании нового понтера компилятор попытается заставить его работать в самом производном классе. Остановка в середине цепочки вывода нарушила бы назначение виртуальных функций.   -  person RedX    schedule 24.08.2011
comment
Просто поместите его в приватный раздел в B? Если я ничего не упустил из виду, это может сработать.   -  person Karel Petranek    schedule 24.08.2011
comment
Я полагаю, вы имеете в виду переопределить, а не перезаписать? Почему для вас важно, чтобы B::func1 не было переопределено?   -  person CB Bailey    schedule 24.08.2011
comment
Я не уверен, но, возможно, это достижимо с помощью спецификаторов доступа и объявления этих функций защищенными.   -  person Rolice    schedule 24.08.2011
comment
Не могли бы вы уточнить, почему это так важно? Я вижу, что многие люди просят об этом, но никогда не видели случая использования, в котором это не было бы защитой от случая Макиавелли.   -  person PlasmaHH    schedule 24.08.2011
comment
gotw.ca/publications/mill18.htm   -  person Flexo    schedule 24.08.2011
comment
GCC добавляет новое ключевое слово final в 4.7.   -  person pythonic metaphor    schedule 24.08.2011
comment
@dark_charlie, Ролис: public/private — это только спецификатор доступа, который определяет, кто может вызывать функцию. Это не имеет ничего общего с переопределением виртуальных функций. Частные виртуальные функции могут быть переопределены в дочерних классах.   -  person Heinzi    schedule 24.08.2011
comment
@PlasmaHH: я получаю класс от CDialogImpl, чтобы реализовать родительский класс для определенных окон. Эти окна должны выполнять некоторую обработку в OnFinalMessage() (например, удалять себя). Когда кто-то наследуется от этого родительского класса, он не должен иметь возможности переопределить OnFinalMessage, потому что это вызовет неприятные утечки памяти.   -  person Heinzi    schedule 24.08.2011
comment
@Heinzi: какой вред будет нанесен, если вы задокументируете эту проблему и сделаете так, чтобы те, кто переопределяет вызов функции, всегда вызывали и вашу функцию? Это должно быть достаточно гибким, чтобы обеспечить возможность добавления поведения путем переопределения, но также и спасти вас. поскольку вы задокументировали это, это их вина, если что-то пойдет не так. не кажется хорошей идеей сделать невозможным неправильное использование класса (Мерфи против Макиавелли)   -  person PlasmaHH    schedule 24.08.2011
comment
Я сторонник другой политики. Я думаю, что лучше выдавать ошибки компилятора или предупреждения компилятора, если класс используется неправильным образом. Документация может быть легко проигнорирована. Чтобы сохранить гибкость, я предлагаю еще одну виртуальную функцию, которую можно переопределить и которая вызывается внутри моей реализации OnFinalMessage().   -  person Heinzi    schedule 24.08.2011


Ответы (3)


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

// C++11 only: indicates that the function cannot be overridden in a subclass
virtual void MemberFunction() final { ... }

Компилятор Microsoft Visual C++ также включает ключевое слово sealed< /a> в качестве расширения, которое работает аналогично ключевому слову C++11 final, но работает только с компилятором Microsoft.

person Adam Rosenfield    schedule 24.08.2011
comment
Это не совсем ключевое слово, а скорее контекстное ключевое слово, верно? То есть я все еще могу использовать final в качестве идентификатора? - person fredoverflow; 24.08.2011
comment
sealed не является расширением Microsoft для C++, это ключевое слово является частью C++\CLI, который, строго говоря, является отдельным языком. - person Kirill V. Lyadvinsky; 24.08.2011
comment
@Кирилл: Да, это так. См. документацию, на которую я ссылался: sealed также допустимо при компиляции для собственных целей (без /clr). - person Adam Rosenfield; 24.08.2011
comment
@ Адам Розенфилд, теперь я вижу это. Не знал, что его можно использовать в родном С++. - person Kirill V. Lyadvinsky; 24.08.2011


Нет. В C++03 нельзя запретить производным классам переопределять1 виртуальные функции базовых классов. Однако базовые классы могут заставить производные (неабстрактные) классы обеспечивать реализацию виртуальных функций (в этом случае виртуальные функции фактически являются чистыми виртуальными функциями).

1. Правильная терминология — переопределить, а не перезаписать.

person Nawaz    schedule 24.08.2011