Domanda

Voglio che una pura classe genitore virtuale chiami un'implementazione figlio di una funzione in questo modo:

class parent
{
  public:
    void Read() { //read stuff }
    virtual void Process() = 0;
    parent() 
    {
        Read();
        Process();
    }
}
class child : public parent
{
  public:
    virtual void Process() { //process stuff }
    child() : parent() { }
}

int main()
{
   child c;
}

Dovrebbe funzionare, ma viene visualizzato un errore non collegato: / Questo utilizza VC ++ 2k3

O non dovrebbe funzionare, sbaglio?

È stato utile?

Soluzione

Altri suggerimenti

In alternativa, crea un metodo factory per creare gli oggetti e rendi privati ??i costruttori, il metodo factory può quindi inizializzare l'oggetto dopo la costruzione.

Funzionerà in generale, ma non per le chiamate all'interno del costruttore della pura classe base virtuale. Al momento della costruzione della classe base, l'override della sottoclasse non esiste, quindi non è possibile chiamarla. Fintanto che lo chiami dopo aver costruito l'intero oggetto, dovrebbe funzionare.

È perché la tua chiamata è nel costruttore. La classe derivata non sarà valida fino a quando il costruttore non sarà completato, quindi il compilatore ha ragione a dartelo per questo.

Esistono due soluzioni:

  1. Effettua la chiamata a Process () nel costruttore della classe derivata
  2. definisce un corpo di funzione vuoto per Process come nell'esempio seguente:
class parent
{
  public:
    void Read() { //read stuff }
    virtual void Process() { }
    parent() 
    {
        Read();
        Process();
    }
}

Con un passo in più potresti semplicemente introdurre una sorta di funzione come

class parent
{
    public:
        void initialize() {
            read();
            process();
        }
}

Devi racchiuderlo in un oggetto che chiama il metodo virtuale dopo che l'oggetto è stato completamente costruito:

class parent
{
  public:
    void Read() { /*read stuff*/ }
    virtual void Process() = 0;
    parent()
    {
        Read();
    }
};

class child: public parent
{
  public:
    virtual void Process() { /*process stuff*/ }
    child() : parent() { }
};

template<typename T>
class Processor
{
    public:
        Processor()
            :processorObj() // Pass on any args here
        {
            processorObj.Process();
        }
    private:
        T   processorObj;

};




int main()
{
   Processor<child> c;
}

Il problema superficiale è che si chiama una funzione virtuale che non è ancora nota (gli oggetti sono costruiti da Parent a Child, quindi lo sono anche itabili). Il tuo compilatore ti ha avvertito di ciò.

Il problema essenziale , per quanto posso vedere, è che si tenta di riutilizzare la funzionalità per eredità. Questa è quasi sempre una cattiva idea. Un problema di progettazione, per così dire :)

In sostanza, si tenta di creare un'istanza di un modello Metodo modello, per separare il cosa dal quando : prima leggere alcuni dati (in qualche modo), quindi elaborarli (in in qualche modo).

Questo probabilmente funzionerà molto meglio con l'aggregazione: assegnare la funzione Elaborazione al metodo Template da chiamare al momento giusto. Forse puoi anche fare lo stesso per la funzionalità di lettura.

L'aggregazione può essere effettuata in due modi:

  1. Uso delle funzioni virtuali (ad es. Runtime Binding)
  2. Uso dei modelli (ad es. Compilare i tempi)

Esempio 1: associazione runtime

class Data {};
class IReader    { public: virtual Data read()            = 0; };
class IProcessor { public: virtual void process( Data& d) = 0; };

class ReadNProcess {
public:
    ReadNProcess( IReader& reader, IProcessor processor ){
       processor.process( reader.read() );
    }
};

Esempio 2: rilegatura compiletime

template< typename Reader, typename Writer > // definitely could use concepts here :)
class ReadNProcess {
public:
     ReadNProcess( Reader& r, Processor& p ) {
         p.process( r.read() );
     }
};
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top