Pregunta

Tengo una clase base que quiero tener este aspecto:

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

El punto es para forzar las clases derivadas para anular I y obligarlo a ser llamada cuando se construye cada objeto. Esto se acostumbra a hacer un poco de contabilidad y necesito saber qué tipo de objeto se está construyendo (pero por lo demás tratar el objeto actual como la clase base).

Esto no funciona debido a que C ++ no permitirá que se llama a una función virtual abstracto desde el constructor.

¿Hay una manera de conseguir el mismo efecto?


este enlace parecería que la respuesta es no hay manera de conseguir lo que quiero. Sin embargo, lo que dice es:

  

La respuesta corta es: no. Una clase base no sabe nada acerca de lo que la clase se deriva de y que es una buena cosa, también. [...] Es decir, el objeto no se convirtió oficialmente en una instancia de Derived1 hasta que el constructor comienza Derived1 :: Derived1.

Sin embargo, en mi caso, no quiero saber lo que es pero lo que hará convertido . De hecho, ni siquiera importa lo que yo vuelva el tiempo que el usuario puede (después del hecho) asignarlo a una clase. Así que podría incluso utilizar algo así como un puntero de retorno y salirse con la suya.

(ahora de nuevo a la lectura de ese enlace)

¿Fue útil?

Solución

No se puede llamar a los métodos virtuales desde el constructor (o para ser más precisos, que puede llamarlos, pero que va a terminar llamando a la función miembro de la clase que se está construyendo). , el problema es que el objeto derivado todavía no existe en ese momento. Hay muy poco que se pueda hacer al respecto, llamar a los métodos virtuales desde el constructor polimórfica es simplemente fuera de la cuestión.

Usted debe reconsiderar su diseño - pasando la constante como un argumento para el constructor, por ejemplo

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

C ++ FAQ para más . Si realmente desea llamar funciones virtuales durante la construcción, leer este .

Otros consejos

Tal vez utilizar un método de fábrica estática en cada tipo derivado? Esta es la manera usual para construir objetos exóticas (es decir: aquellos con requisitos de inicialización muy específicos). En .NET, que he llegado a apreciar

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

Llamar a métodos virtuales en constructores de base está mal visto en general acerca, ya que nunca puede estar seguro de la conducta de un método particular, y (como alguien más ya se ha señalado) serán aún no han sido llamados constructores derivados.

Eso no funcionará como la clase derivada no existe todavía cuando se ejecuta el constructor de la clase de 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;
    }
};

En su lugar se podría añadir los argumentos al constructor de la clase base:

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

    virtual ~Base() = 0
    {
    }
};

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

    virtual ~Derived()
    {
    }
};

O si usted es realmente aficionado a la programación orientada a objetos también se puede crear un par de clases adicionales:

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()
    {
    }
};

Lo que necesita es la construcción de dos fases . Utilice la curación del programador universal: Añadir otra capa de direccionamiento indirecto.

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