constness para los miembros de la clase de referencia

Tengo un par de clases, una de las cuales guarda referencia al objeto de la otra:

class Inner {};

class Outer {
    Inner & in;

public:
    Outer(Inner & in) : in(in) {}
};

¿Qué sucede si tengo que crear un objeto externo desde la referencia constante a la interna? ¿Tengo que escribir una clase específica, digamos OuterConst, para esto?

UPD: ¿Alguna buena solución con plantillas? Para evitar la duplicación de código en la clase OuterConst.

UPD2: cuando Inner viene sin const, debería ser modificable (por lo que no puedo simplemente agregar const al miembro Inner en la implementación actual de Outer).

preguntado el 20 de junio de 11 a las 21:06

4 Respuestas

Puede almacenar una referencia constante y usar const_cast para tirar el const cuando sea necesario. Si agrega alguna verificación de tiempo de ejecución, también es seguro.

class Inner { /* ... */ };

class Outer {
    Inner const & in;
    bool const inIsConst;

    Inner & inMutable()
    {
        if (inIsConst)
            throw std::logic_error("in is const.");
        else
            return const_cast<Inner &>(in);
    }

public:
    Outer(Inner const & in) : in(in), inIsConst(true) {}
    Outer(Inner & in) : in(in), inIsConst(false) {}

    // always safe
    void Foo() { std::cout << in.getFoo(); }

    // will throw if *this was constructed with a const Inner
    void Bar() { inMutable().setFoo(in.getFoo() + 1); }
};

Y, por supuesto, siempre puede dividir esto en dos clases: una que no puede cambiar in, y otro que puede.

Para hacer esto, puede derivar la clase que puede cambiar in de la clase que no puede. O puede derivar tanto de una clase base común que tiene las funciones comunes como miembros protegidos, como hacer públicas las apropiadas con using Base::Function en las clases derivadas.

Respondido el 21 de junio de 11 a las 01:06

¿Qué sucede si tengo que crear un objeto externo desde la referencia constante a la interna?

Bueno, no puedes. Eso es practicamente todo. Si Outer solo necesita llamar a funciones miembro const de Inner, entonces conviértalo en una referencia const; de lo contrario, su clase depende de un objeto Inner mutable y no debe crear un objeto Outer a partir de una referencia const.

Respondido el 21 de junio de 11 a las 01:06

La pregunta es si Outer necesita modificar Inner a través de in. Si es así, debes mantener in como una Inner &. En este caso, si tiene un const Inner & entonces, por supuesto, no puedes pasárselo a Outer, porque la referencia no le permite modificar la referencia Inner, pero Outer necesita modificar Inner.

If Outer no necesita modificar Inner, entonces deberías escribir in como una const Inner &, en ese caso Outer se puede inicializar con un Inner & o const Inner &.

Ciertamente puedes escribir:

class Inner {};

template <class T>
class Outer {
    T& in;

public:
    Outer(T& in) : in(in) {}
};

y luego inicializar objetos de tipo Outer<Inner> or Outer<const Inner>. Sin embargo, Outer debe hacer algo diferente en estos dos casos, ya que de lo contrario podría hacer in a const Inner &. Y en ese caso, probablemente sea mejor escribir clases separadas, de modo que sea explícito que Outer hace algo diferente.

Respondido el 21 de junio de 11 a las 01:06

Depende. Si los dos roles de Outer son diferentes para diferentes constness'es (uno debe ser editado, el otro no), entonces sí.

Pero si los dos roles son idénticos (eso significa que nunca se realizan cambios en una referencia constante o no constante), entonces siempre tome una const Inner& como parámetro. Si se pasa un parámetro que no es constante, se "promocionará" automáticamente a un const uno.

Respondido el 21 de junio de 11 a las 01:06

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.