Domanda

Ho una classe base che voglio assomigliare a questa:

class B
{
    // should look like: int I() { return someConst; }
    virtual int I() = 0;
    public B() { something(I()); }
}

Il punto è forzare l'override delle classi derivate I e forzarlo a essere chiamato quando ogni oggetto viene costruito.Questo viene utilizzato per fare un po' di contabilità e ho bisogno di sapere che tipo di oggetto si sta costruendo (ma per il resto tratto l'oggetto corrente come la classe base).

Questo non funziona perché C++ non ti consente di chiamare una funzione virtuale astratta dal costruttore.

Esiste un modo per ottenere lo stesso effetto?


Basato su questo link sembrerebbe che la risposta sia che non c'è modo di ottenere ciò che voglio.Comunque quello che dice è:

La risposta breve è:NO.Una classe base non sa nulla della classe da cui deriva, ed è anche una buona cosa. [...] Cioè, l'oggetto non diventa ufficialmente un'istanza di Derived1 finché non inizia il costruttore Derived1::Derived1.

Tuttavia nel mio caso non voglio sapere di cosa si tratta È ma cosa sarà diventare.In effetti, non mi interessa nemmeno ciò che ottengo finché l'utente può (dopo il fatto) mapparlo a una classe.Quindi potrei anche usare qualcosa come un puntatore di ritorno e farla franca.

(ora torniamo a leggere quel link)

È stato utile?

Soluzione

Non puoi chiamare metodi virtuali dal costruttore (o per essere più precisi, tu Potere chiamali, ma finirai per chiamare la funzione membro della classe attualmente in costruzione), il problema è che l'oggetto derivato non esiste ancora in quel momento.C'è molto poco che puoi fare al riguardo, chiamare i metodi virtuali dal costruttore in modo polimorfico è semplicemente fuori questione.

Dovresti ripensare il tuo progetto, ad esempio passando la costante come argomento al costruttore.

class B
{
public:
    explicit B(int i)
    {
        something(i);
    }
};

Vedere Domande frequenti su C++ per più.Se tu Veramente vuoi chiamare funzioni virtuali durante la costruzione, leggi questo.

Altri suggerimenti

Forse utilizzare un metodo di fabbrica statico su ciascun tipo derivato?Questo è il modo usuale per costruire oggetti esotici (leggi:quelli con requisiti di inizializzazione molto specifici) in .NET, che ho imparato ad apprezzare.

class Base
{
  protected Base(int i)
  {
    // do stuff with i
  }
}

class Derived : public Base
{
  private Derived(int i)
    : Base(i)
  {
  }

  public Derived Create()
  {
    return new Derived(someConstantForThisDerivedType);
  }
}

Chiamare metodi virtuali nei costruttori di base è generalmente disapprovato, poiché non si può mai essere certi del comportamento di un particolare metodo e (come già sottolineato da qualcun altro) i costruttori derivati ​​non saranno ancora stati chiamati.

Ciò non funzionerà poiché la classe derivata non esiste ancora quando viene eseguito il costruttore della classe base:

class Base
{
public:
    Base()
    {
        // Will call Base::I and not Derived::I because
        // Derived does not yet exist.
        something(I());
    }

    virtual ~Base() = 0
    {
    }

    virtual int I() const = 0;
};

class Derived : public Base
{
public:
    Derived()
     : Base()
    {
    }

    virtual ~Derived()
    {
    }

    virtual int I() const
    {
        return 42;
    }
};

Invece potresti aggiungere gli argomenti al costruttore della classe base:

class Base
{
public:
    explicit Base(int i)
    {
        something(i);
    }

    virtual ~Base() = 0
    {
    }
};

class Derived : public Base
{
public:
    Derived()
     : Base(42)
    {
    }

    virtual ~Derived()
    {
    }
};

Oppure, se sei davvero appassionato di OOP, potresti anche creare un paio di classi aggiuntive:

class Base
{
public:
    class BaseConstructorArgs
    {
    public:
        virtual ~BaseConstructorArgs() = 0
        {
        }

        virtual int I() const = 0;
    };

    explicit Base(const BaseConstructorArgs& args)
    {
        something(args.I());
    }

    virtual ~Base() = 0
    {
    }
};

class Derived : public Base
{
public:
    class DerivedConstructorArgs : public BaseConstructorArgs
    {
    public:
        virtual ~DerivedConstructorArgs()
        {
        }

        virtual int I() const
        {
            return 42;
        }
    };

    Derived()
     : Base(DerivedConstructorArgs())
    {
    }

    virtual ~Derived()
    {
    }
};

Ciò di cui hai bisogno è costruzione in due fasi.Usa la cura del Programmatore Universale:Aggiungi un altro livello di indiretto.

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