Pregunta

¿Para qué usan aquí los constructores de clase base abstracta C ++ en el campo? Estoy hablando de clases de interfaz pura que no tienen miembros de datos ni miembros virtuales no puros.

¿Alguien puede demostrar expresiones idiomáticas que usen constructores ABC de una manera útil? ¿O es simplemente intrínseco a la naturaleza del uso de ABC para implementar interfaces que permanecen vacías, en línea y protegidas?

¿Fue útil?

Solución

  

¿Alguien puede demostrar expresiones idiomáticas que usen constructores ABC de una manera útil?

Aquí hay un ejemplo, aunque es un ejemplo artificial y poco común.

Puede usarlo para mantener una lista de todas las instancias:

class IFoo
{
private:
  //static members to keep a list of all constructed instances
  typedef std::set<IFoo*> Set;
  static Set s_set;

protected:
  //new instance being created
  IFoo()
  {
    s_set.insert(this);
  }

public:
  //instance being destroyed
  virtual ~IFoo()
  {
    s_set.remove(this);
  }

  ... plus some other static method and/or property
      which accesses the set of all instances ...
};
  

¿O es intrínseco a la naturaleza del uso de ABC para implementar interfaces que permanecen vacías, en línea y protegidas?

¡Más generalmente no se declaran en absoluto! No hay razón para declararlos:

  • Vacío e inline = > ¿Por qué molestarse en declararlo?
  • Protegido = > el ABC probablemente ya tiene algunos métodos virtuales puros y, por lo tanto, ya no se puede instanciar, excepto como una subclase.

Otros consejos

Suponga que hay un comportamiento común para todas las clases derivadas. Como registrarse en algún registro externo o verificar la validez de algo.

Todo este código común se puede colocar en el constructor de la clase base, y se llamará implícitamente desde los constructores de cada una de las clases derivadas.

¿Cómo podría utilizar el constructor de una clase base abstracta para algo?

Suponga que tiene una clase base abstracta B y una clase derivada D. Cuando se crea un objeto de tipo D, primero se llama al constructor de B, pero en ese punto, el objeto " es " todavía del tipo B (consulte aquí ) - en particular, llamar a cualquier función virtual desde el cuerpo del constructor de B llamará a las implementaciones propias de B de esas funciones. Pero si B es una clase abstracta pura, ninguna de esas funciones virtuales está definida, por lo que el programa se bloqueará de inmediato.

Supongo que pretendías que el constructor de B llamara a la implementación de una función virtual de la clase más derivada (por ejemplo, D), ¿verdad? Sería una mala idea en general porque el objeto de D aún no está completamente construido, por lo que cualquier acceso a las variables miembro en D desde la implementación de D de la función virtual accedería a la memoria no inicializada.

Recuerde: " La adquisición de recursos es la inicialización " .

A veces usamos clases base abstractas como algún tipo de mecanismo de bloqueo. Por ejemplo, en un entorno de subprocesos múltiples, donde varios subprocesos necesitan compartir un solo recurso, entonces un subproceso puede usar el constructor como una forma de adquirir el recurso y el destructor para liberar el recurso

void PlayWithPaintBallGun(Target &target)
{
    PaintBallGun paintBallGun;    // constructor waits until the gun is free,
                                  // then picks it up.

    paintBallGun.Aim(target);     // Shoot something
    paintBallGun.Fire();          //

                                  // Clever! The destructor is automatically
                                  // called when it goes out of scope. So we
                                  // can't forget to put the gun down.
}

Hugo

No puedo pensar en muchos ejemplos útiles. Una clase sin miembros de datos no tiene estado y, por lo tanto, no puede inicializar nada. Sin embargo, puede hacer que el constructor / destructor haga el registro por usted. Por ejemplo, para registrar la creación / destrucción de todos los objetos Visitantes:

class Visitor {
public:
    Visitor() {
        std::cout << "Visitor@" << this << " created" 
                  << std::endl;
    }

    virtual ~Visitor() {
        std::cout << "Visitor@" << this << " destroyed" 
                  << std::endl;
    }

    virtual void visitA(A*) = 0;
    virtual void visitB(B*) = 0;
    // ...
};

generalmente es únicamente para inicializar miembros a valores sensibles.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top