2009-05-13 2 views
18

Предположим, что у меня есть виртуальная функция foo() в классе B, и мне нужно немного другое поведение в одном из производных классов B, класс D. Можно ли создать функцию переопределения D :: foo() и вызывать B :: foo() оттуда после обработки специального случая? Пример:Вызов переопределенной функции из функции переопределения

void D::foo() 
{ 
    if (/*something*/) 
    // do something 
    else 
    B::foo(); 
} 

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

ответ

17

Это прекрасно. Фактически, канонический способ выполнения некоторых операций - это вызов метода базового класса, а затем делать что угодно (или наоборот). Я думаю о operator= здесь. Конструкторы обычно работают так же, даже если это немного замаскировано в списке инициализации.

4

Да, это так.

+3

Common, стандартный, обычный, типичный, широко используемый. Действительно, абсолютно необходимо иметь возможность сделать это. –

1

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

5

Да, это полностью нормально, если вы не нарушаете Принцип замещения Лискова.

0

Да, это то, что ваш компилятор делает для вас каждый раз, когда он генерирует конструктор и деструктор: называть, например, мать. Я часто полагаюсь на этот «трюк» в моем собственном коде.

1

Все в порядке. Синтаксис, который вы дали, также может использоваться для временного отключения полиморфизма, т. Е. Когда вы вызываете метод obj-> B :: foo(), выбирается из класса B независимо от того, является ли foo() виртуальным или нет, и если obj является экземпляром B или нет (это должен быть экземпляр класса, расширяющего B, хотя).

+0

Вы не можете гарантировать, что функция не вызывается из подкласса _B_, и в этом случае вы вообще ничего не поворачиваете. – xtofl

+0

@xtofl: Вы говорите, что если у меня есть B расширяет A, C расширяет B, то есть A B :: foo() разрешен для вызова A :: foo()? – 2009-05-13 10:28:16

+0

@xtolf: Я только что подтвердил свой ответ, и это кажется правильным. – 2009-05-13 10:38:26

0

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

Вы можете столкнуться fragile base class вопрос двумя способами:

  • Допуская B::foo() обеспечивает общее поведение для всей иерархии (то есть, позабыв метод не всегда называют)
  • Противные задачи в зависимости от того, что // do something фактически.!

Для полноты отметим симметричный подход к проектированию: Template pattern (базовая реализация вызова конкретных суб-часть)

Смежные вопросы