Puntero a objeto como argumento de un constructor

Bien, digamos que tengo una clase base abstracta aleatoria Base y tengo una clase Foo que contiene un puntero a esta clase base como miembro de datos. Entonces

class Foo
{
    public:
        Foo(Base*);

    private:
        Base* ptr;
}

Ahora, la razón por la que uso un puntero a la clase base es porque quiero poder elegir qué clase derivada mi Foo objeto tiene un puntero a. Ahora, la parte complicada es, para mí, la implementación del constructor para Foo.

Si lo hago asi

Foo::Foo(Base* _ptr)
{
    Foo::ptr = _ptr;
};

sería posible para el usuario ajustar el objeto señalado por Foo::ptr desde _ptr seguirá existiendo después de que el constructor haya terminado. No puedo hacer que el objeto señalado por _ptr constante porque Foo::ptr necesita actualizarse regularmente. Ahora estaba pensando en agregar una línea _ptr = NULL al final del constructor, pero eso también podría ser peligroso, ya que el usuario podría intentar desreferenciar _ptr.

La única manera que se me ocurre para hacer este trabajo es hacer una copia del objeto señalado por _ptr e inicializando Foo::ptr a la dirección de esa copia. Pero entonces el objeto señalado por _ptr necesitaría tener una función miembro Clone() o algo similar porque no puedo llamar al constructor de copia para un objeto del cual no conozco la clase en tiempo de compilación.

Entonces, ¿hay alguna manera elegante de hacer esto si no hay Clone()? ¿O es realmente la única posibilidad?

preguntado el 03 de mayo de 12 a las 20:05

Si usa C++ 11, podría resolver esto usando la semántica de movimiento. -

Agregar "_ptr = NULL" no haría nada, ya que "_ptr" se pasa por valor al constructor. -

¿Qué pasa con un clone ¿método? -

@DavidBrown No creo que haya nada malo en particular, pero significa que el usuario tendría que limpiar su propio desorden, es decir, tendría que eliminar _ptr ellos mismos. No sé por qué, pero realmente no me sienta bien. Tal vez me equivoque y el Clone() El método está bien, pero me gustaría saber las alternativas, no obstante. -

2 Respuestas

Construir a partir de un unique_ptr. De esa manera, su usuario no tiene acceso al puntero después de que se haya utilizado en la creación de un Foo objeto (a menos que realmente quiera y use get).

p.ej

#include <memory>
struct Bar {};

struct Foo {
  Foo(std::unique_ptr<Bar>&& ptr) : ptr_(std::move(ptr)) {}
  std::unique_ptr<Bar> ptr_;
};

int main()
{
  std::unique_ptr<Bar> tt(new Bar());
  Foo f(std::move(tt));

  return 0;
}

contestado el 03 de mayo de 12 a las 20:05

Así que esto todavía funcionaría con std::unique_ptr<DerivedFromBar> tt(new DerivedFromBar()); en la main() ¿función? Y el usuario necesitaría saber que tiene que usar un unique_ptr? ¿O es posible un lanzamiento implícito de un puntero regular a un unique_ptr? creo que no - Wouter

@Wouter unique_ptr<DerivedFromBar> se convierte a unique_ptr<Bar>. El punto de unique_ptr aquí es que claramente estableces la propiedad en cada momento. El usuario lo construye, lo usa, y tan pronto como solía construir un Foo renuncia a la propiedad mediante el uso move en eso. - PMR

Oh sí, lo siento, quise decir std::unique_ptr<Bar> tt(new DerivedFromBar());, pero yo veo. Entonces unique_ptr actúa como un puntero regular (con propiedad explícita en todo momento), pero el elenco de regular a unique_ptr Pregunté acerca de que probablemente no existe, ¿verdad? Dado que no hay forma de verificar si es el único puntero a ese objeto. - Wouter

@Wouter No necesariamente es necesario new el puntero en el momento de unique_ptr construcción, pero puede construir el unique_ptr más tarde desde un puntero ya asignado. Aunque no hay una conversión implícita a un unique_ptr. Eso sería muy peligroso. En esta solución, su cliente es activamente consciente de ceder el control. - PMR

Está bien, eso es lo que pensé. ¡Gracias! - Wouter

Una alternativa es usar punteros inteligentes. De esa forma, la propiedad se asigna a la implementación del puntero inteligente.

contestado el 03 de mayo de 12 a las 20:05

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