Pregunta C ++ anula el método virtual puro con método virtual puro


¿Alguna vez tiene sentido anular un método virtual puro con otro método virtual puro? ¿Existen diferencias funcionales o quizás razones de estilo de código para preferir una de las siguientes opciones sobre la otra?

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; }
};

8
2018-04-17 19:51


origen


Respuestas:


Ambos códigos producen el mismo efecto: clase Abstract es abstracto y no puedes instanciarlo.

Sin embargo, hay una diferencia semántica entre las dos formas:

  • La primera forma recuerda claramente que la clase Abstract es abstracto (solo en caso de que su nombre no sea lo suficientemente independiente ;-)). No solo lo recuerda: también lo asegura al asegurarse de que el método sea puramente virtual.
  • La segunda forma significa que la clase Abstract hereda todo exactamente de Interface. Es abstracto si y solo si su clase base es.

Esto tiene consecuencias en las evoluciones futuras de su código. Por ejemplo, si un día cambia de opinión y desea que la interfaz tenga una implementación predeterminada para method() :

  • En la primera forma Absract permanece abstracto y no heredará la implementación predeterminada del método.
  • La segunda forma asegura que Abstact seguiría heredando y comportándose exactamente como Interface.

Personnally encuentro que la segunda forma es más intuitiva y asegura una mejor separación de las preocupaciones. Pero puedo imaginar que podría haber algunas situaciones en las que la primera forma realmente podría tener sentido.


6
2018-04-17 21:20



La especificación pura de un método obliga a anular, pero no impide que proporcione una implementación del método. La siguiente es una técnica rara, pero a veces útil.

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;
 }

Esto a veces es útil si hay varias clases derivadas de Resumen que necesitan alguna funcionalidad común, pero también necesitan agregar un comportamiento específico de clase. [y debería ser forzado a proporcionar ese comportamiento.]


5
2018-04-17 21:20