Domanda

Per cosa le persone qui usano i costruttori di C ++ Abstract Base Class sul campo? Sto parlando di classi di interfaccia pure senza membri di dati e senza membri virtuali non puri.

Qualcuno può dimostrare qualche linguaggio che usa i costruttori ABC in modo utile? Oppure è intrinseco alla natura dell'uso degli ABC per implementare interfacce che rimangono vuote, in linea e protette?

È stato utile?

Soluzione

  

Qualcuno può dimostrare qualche linguaggio che usa i costruttori ABC in modo utile?

Ecco un esempio, sebbene sia un esempio inventato, non comune.

Potresti usarlo per mantenere un elenco di tutte le istanze:

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 è solo intrinseco alla natura dell'uso degli ABC per implementare interfacce che rimangono vuote, in linea e protette?

Più di solito non vengono dichiarati affatto! Non c'è motivo di dichiararli:

  • Vuoto e in linea = > perché preoccuparsi di dichiararlo?
  • Protetto = > l'ABC probabilmente ha già alcuni metodi virtuali puri e quindi non può già essere istanziato se non come sottoclasse.

Altri suggerimenti

Supponiamo che ci sia un comportamento comune per tutte le classi derivate. Come registrarsi in un registro esterno o verificare la validità di qualcosa.

Tutto questo codice comune può essere inserito nel costruttore della classe base e verrà chiamato implicitamente dai costruttori di ciascuna delle classi derivate.

In che modo potrebbe utilizzare il costruttore di una classe base astratta per qualsiasi cosa?

Supponi di avere una classe base astratta B e una classe derivata D. Quando viene creato un oggetto di tipo D, il costruttore di B viene chiamato per primo, ma a quel punto l'oggetto "è" ancora di tipo B (vedi qui ) - in particolare, chiamare qualsiasi funzione virtuale dal corpo del costruttore di B chiamerà le implementazioni di B di tali funzioni. Ma se B è una classe astratta pura, nessuna di quelle funzioni virtuali è definita, quindi il programma andrà in crash immediatamente.

Immagino che tu intendessi che il costruttore di B chiamasse l'implementazione di una funzione virtuale della classe più derivata (ad es. D), giusto? Questa sarebbe una cattiva idea in generale perché l'oggetto di D non è ancora completamente costruito, quindi qualsiasi accesso alle variabili membro in D dall'implementazione della funzione virtuale da parte di D accederà alla memoria non inizializzata.

Ricorda: " L'acquisizione delle risorse è l'inizializzazione " .

A volte usiamo le classi base astratte come una sorta di meccanismo di blocco. Ad esempio, in un ambiente multi-thread, in cui diversi thread devono condividere una singola risorsa, un thread può utilizzare il costruttore come un modo per acquisire la risorsa e il distruttore per rilasciare la risorsa

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

Non riesco a pensare a molti esempi utili. Una classe senza membri dei dati non ha stato e quindi non può inizializzare nulla. Tuttavia, puoi fare in modo che il costruttore / distruttore esegua la registrazione per te. Ad esempio, per registrare la creazione / distruzione di tutti gli oggetti Visitor:

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

di solito è solo per inizializzare i membri su valori sensibili.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top