c++ - reales - manual android studio avanzado




La mejor manera de declarar una interfaz en C++ 11 (4)

Al reemplazar la class palabras con struct , todos los métodos serán públicos de forma predeterminada y puede guardar una línea.

No hay necesidad de proteger al constructor, ya que de todos modos no se puede crear una instancia de una clase con métodos virtuales puros. Esto va también para el constructor de copia. El constructor predeterminado generado por el compilador estará vacío ya que no tiene ningún miembro de datos, y es completamente suficiente para sus clases derivadas.

Tienes razón en preocuparte por el operador = ya que el generador generado por el compilador hará lo incorrecto. En la práctica, nadie se preocupa por eso porque copiar un objeto de interfaz a otro nunca tiene sentido; No es un error que sucede comúnmente.

Los destructores para una clase heredable siempre deben ser públicos y virtuales, o protegidos y no virtuales. Prefiero público y virtual en este caso.

El resultado final es solo una línea más larga que el equivalente de Java:

struct Testable {
    virtual void test() = 0;
    virtual ~Testable();
};

Como todos sabemos, algunos idiomas tienen la noción de interfaces. Esto es Java:

public interface Testable {
  void test();
}

¿Cómo puedo lograr esto en C ++ (o C ++ 11) de la forma más compacta y con poco ruido de código? Apreciaría una solución que no necesitaría una definición separada (deje que el encabezado sea suficiente). Este es un enfoque muy simple que incluso encuentro buggy ;-)

class Testable {
public:
  virtual void test() = 0;
protected:
  Testable();
  Testable(const Testable& that);
  Testable& operator= (const Testable& that);
  virtual ~Testable();
}

Esto es solo el comienzo ... y ya no querría más. ¿Cómo mejorarlo? ¿Quizás hay una clase base en algún lugar del espacio de nombres estándar hecho solo para esto?


De acuerdo con Scott Meyers (Effective Modern C ++): al declarar interfaz (o clase base polimórfica), se necesita un destructor virtual para obtener resultados adecuados de operaciones como delete o typeid en un objeto de clase derivado al que se accede a través de un puntero o referencia de clase base.

virtual ~Testable() = default;

Sin embargo, un destructor declarado por el usuario suprime la generación de las operaciones de movimiento, por lo que para admitir las operaciones de movimiento debe agregar:

Testable(Testable&&) = default; 
Testable& operator=(Testable&&) = default;

La declaración de las operaciones de movimiento deshabilita las operaciones de copia y también necesita:

Testable(const Testable&) = default;
Testable& operator=(const Testable&) = default;

Y el resultado final es:

class Testable 
{
public:
    virtual ~Testable() = default; // make dtor virtual
    Testable(Testable&&) = default;  // support moving
    Testable& operator=(Testable&&) = default;
    Testable(const Testable&) = default; // support copying
    Testable& operator=(const Testable&) = default;

    virtual void test() = 0;

};

Qué pasa:

class Testable
{
public:
    virtual ~Testable() { }
    virtual void test() = 0;
}

En C ++ esto no tiene implicaciones sobre la posibilidad de copiar las clases secundarias. Todo lo que dice es que el niño debe implementar la test (que es exactamente lo que desea para una interfaz). No puede crear una instancia de esta clase, por lo que no tiene que preocuparse por ningún constructor implícito, ya que nunca se puede llamar directamente como el tipo de interfaz principal.

Si desea imponer que las clases secundarias implementen un destructor, puede hacerlo también puro (pero todavía tiene que implementarlo en la interfaz).

También tenga en cuenta que si no necesita destrucción polimórfica, puede optar por hacer que su destructor protegido no sea virtual.


Tenga en cuenta que la "regla de tres" no es necesaria si no está administrando punteros, manejadores o todos los miembros de datos de la clase tienen sus propios destructores que administrarán cualquier limpieza. También en el caso de una clase base virtual, porque la clase base nunca puede ser instanciada directamente, no es necesario declarar un constructor si todo lo que desea es definir una interfaz que no tenga miembros de datos ... el compilador los valores por defecto están bien El único elemento que necesitaría mantener es el destructor virtual si planea llamar a delete en un puntero del tipo de interfaz. Entonces, en realidad su interfaz puede ser tan simple como:

class Testable 
{
    public:
        virtual void test() = 0;  
        virtual ~Testable();
}




abstract