2015-04-17 3 views
5

Имеет ли смысл переопределять чистый виртуальный метод другим чистым виртуальным методом? Существуют ли какие-либо функциональные различия или, возможно, причины стиля кода, чтобы предпочесть один из следующих вариантов по сравнению с другим?C++ переопределяет чистый виртуальный метод с использованием чистого виртуального метода

class Interface { 
public: 
    virtual int method() = 0; 
}; 

class Abstract : public Interface { 
public: 
    int method() override = 0; 
}; 

class Implementation : public Abstract { 
public: 
    int method() override { return 42; } 
}; 

Versus:

class Interface { 
public: 
    virtual int method() = 0; 
}; 

class Abstract : public Interface {}; 

class Implementation : public Abstract { 
public: 
    int method() override { return 42; } 
}; 
+1

Это могло бы только сообщить кому-то, кто читает ваш код. * «Дорогой человек, просматривающий мой абстрактный код ... обратите внимание, что этот класс действительно имеет виртуальную функцию». –

ответ

4

Оба кода дают одинаковый эффект: класс Abstract является абстрактным, и вы не можете создать его экземпляр.

Существует, однако, семантическое различие между этими двумя формами:

  • Первая форма напоминает ясно, что класс Abstract является абстрактным (только в случае, если это имя не будет самостоятельно sepaking достаточно ;-)). Он не только напоминает это: он также обеспечивает его, убедившись, что метод является чисто виртуальным.
  • Вторая форма означает, что класс Abstract наследует все точно от Interface. Он абстрактный, если и только если его базовый класс.

Это имеет последствия для будущих эволюций вашего кода. Например, если один день вы передумали и хотите взаимодействовать, чтобы иметь реализацию по умолчанию для method():

  • В первой форме Absract остается абстрактным и не будет наследовать реализацию по умолчанию метода.
  • Вторая форма гарантирует, что Abstact будет продолжать наследовать и вести себя точно так же, как Interface.

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

4

Чистая спецификация метода вызывает переопределение, но это не мешает вам реализовать реализацию метода. Ниже приводится редкая, но иногда полезная техника.

class Interface 
{ 
    virtual void method() = 0; 
}; 

class Abstract : public Interface 
{ 
    virtual void method() = 0; 
} 
inline void Abstract::method() 
{ 
    do something interesting here; 
} 

class Concrete : public Abstract 
{ 
    virtual void method(); 
} 

inline void Concrete::method() 
{ 
    // let Abstract::method() do it's thing first 
    Abstract::method(); 
    now do something else interesting here; 
} 

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

+1

Обратите внимание на 'inline', чтобы сделать код понятным, если все появилось в заголовке. На практике вам, вероятно, следует избегать встроенных виртуальных методов! –

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