Question

Pourquoi les gens ici utilisent-ils les constructeurs de classes de base abstraites C ++ sur le terrain? Je parle de classes d'interface pures n'ayant aucun membre de données et aucun membre virtuel non pur.

Quelqu'un peut-il démontrer des expressions qui utilisent les constructeurs ABC de manière utile? Ou est-il simplement inhérent à la nature d'utiliser ABC pour mettre en oeuvre des interfaces qu'elles restent vides, en ligne et protégées?

Était-ce utile?

La solution

  

Quelqu'un peut-il démontrer des expressions qui utilisent les constructeurs ABC de manière utile?

Voici un exemple, bien que ce soit un exemple artificiel et peu commun.

Vous pouvez l'utiliser pour conserver une liste de toutes les instances:

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

Ou est-il simplement inhérent à la nature d'utiliser ABC pour implémenter des interfaces qu'elles restent vides, en ligne et protégées?

Plus généralement, ils ne sont tout simplement pas déclarés! Il n'y a aucune raison de les déclarer:

  • Vide et en ligne = > pourquoi se donner la peine de le déclarer?
  • Protected = > ABC a probablement déjà des méthodes virtuelles pures et ne peut donc déjà être instancié que sous forme de sous-classe.

Autres conseils

Supposons qu'il existe un comportement commun à toutes les classes dérivées. Comme s'inscrire dans un registre externe ou vérifier la validité de quelque chose.

Tout ce code commun peut être placé dans le constructeur de la classe de base et sera appelé implicitement à partir des constructeurs de chacune des classes dérivées.

Comment peut-on utiliser le constructeur d'une classe de base abstraite pour quoi que ce soit?

Supposons que vous avez une classe de base abstraite B et une classe dérivée D. Lorsqu'un objet de type D est créé, le constructeur de B est appelé en premier, mais à ce stade, l'objet "est". toujours de type B (voir ici ) - en particulier, l'appel de toutes les fonctions virtuelles à partir du corps du constructeur de B appellera les propres implémentations de B de ces fonctions. Mais si B est une classe abstraite pure, aucune de ces fonctions virtuelles n’est définie et le programme se bloque immédiatement.

J'imagine que vous aviez l'intention que le constructeur de B appelle la mise en œuvre de la fonction la plus dérivée (par exemple, D) d'une fonction virtuelle, n'est-ce pas? Ce serait une mauvaise idée en général, car l’objet de D n’est pas encore complètement construit. Ainsi, tout accès aux variables membres de D depuis l’implémentation de la fonction virtuelle dans D accéderait à la mémoire non initialisée.

N'oubliez pas: "L'acquisition d'une ressource est une initialisation" .

Nous utilisons parfois des classes de base abstraites comme mécanisme de verrouillage. Par exemple, dans un environnement multi-thread, où plusieurs threads doivent partager une seule ressource, un thread peut utiliser le constructeur pour acquérir la ressource et le destructeur pour libérer la ressource.

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

Je ne peux pas penser à beaucoup d'exemples utiles. Une classe sans membre de données n'a pas d'état et ne peut donc rien initialiser. Vous pouvez toutefois demander au constructeur / destructeur de se connecter pour vous. Par exemple, pour consigner la création / destruction de tous les objets visiteur:

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

généralement, il s’agit uniquement d’initialiser les membres sur des valeurs sensibles.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top