2010-09-29 12 views
15

Estoy heredando una clase y me gustaría llamar a uno de sus constructores. Sin embargo, tengo que procesar algunas cosas (que no requieren nada de la clase base) antes de llamarlo. ¿Hay alguna manera en que pueda llamarlo más tarde en lugar de llamarlo en la lista de inicializadores? Creo que esto se puede hacer en Java y C#, pero no estoy seguro de C++.Llamar a un constructor de clase base más tarde (no en la lista de inicializadores) en C++

Los datos que necesito pasar en el constructor no se pueden reasignar más tarde, por lo que no puedo simplemente llamar a un constructor predeterminado e inicializarlo más tarde.

Respuesta

27

¿Hay alguna manera en que pueda llamarlo más tarde en lugar de llamarlo en la lista de inicializadores?

No, no puede. El constructor de la clase base debe invocarse en la lista de inicializadores y debe llamarse primero.

De hecho, si lo omite allí, el compilador simplemente agregará la llamada implícitamente.

Creo que esto se puede hacer en Java y C#, pero no estoy seguro acerca de C++.

Ni C ni Java permiten esto tampoco.

Lo que puede hacer, sin embargo, es llamar a un método como argumento de la llamada al constructor de la clase base. Esto entonces se procesa antes de que el constructor:

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

private: 
    static int some_function() { return 42; } 
}; 
+1

Gracias, no pensé en llamar a una función, así que funcionará pero va a ser un poco complicado porque el constructor tiene 2 parámetros. Aceptaré esta respuesta cuando pueda (a menos que salga una mejor, por supuesto). Por cierto, tienes razón sobre no poder hacer esto en Java y C#, pensé que era posible en Java porque se hace usando 'super (...)' en el cuerpo del método, pero ahora me doy cuenta de que debe ser la primera línea. – placeholder

+4

+1 Debería establecer some_function() static para documentar el hecho de que no utiliza ninguna de las variables de instancia de la clase (que no se han inicializado). –

+0

Interesante, nunca visto eso hecho antes. Supongo que la función llamada puede ser una función de clase derivada. – PatrickV

-2
struct base{ 
    base(int x){} 
}; 

struct derived : base{ 
    derived(int x) : base(x){} 
}; 

Así es como constructores de clase de base se invocan en C++ de la lista de inicialización de clase derivada.

+4

Esto no es lo que está preguntando. –

1

EN MI NO creo que sea posible diferir la llamada al constructor de la clase base de la manera que usted mencionó.

0

Guau, todos éramos jóvenes una vez. Esta respuesta no funcionará, entonces no la use. Contenido dejado para propósitos históricos.

Si usted tiene un control total sobre la clase base, me gustaría recomendar la adición de un método protegido de hacer la inicialización de clase, que sea virtual, y poner los detalles de su implementación clase derivada de ella antes de que llama a su base:

class Base 
{ 
public: 
    Base() 
    { 
     Initialize(); 
    } 
protected: 
    virtual void Initialize() 
    { 
     //do initialization; 
    } 
}; 

class Derived : Base 
{ 
public: 

    Derived() : Base() 
    { 
    } 
protected: 
    virtual void Initialize() 
    { 
     //Do my initialization 
     //call base 
     Base::Initialize(); 
    } 
}; 
+0

Desafortunadamente, no tengo control de la clase base. – placeholder

+0

Es probable que no pueda cumplir su objetivo. Si publica más código, podríamos encontrar algo, pero nunca lo he visto en C++. – PatrickV

+0

No me gusta la idea. La construcción en dos fases siempre es propensa a errores. – sbi

11

Como dijeron varias personas que respondieron, no puede retrasar la invocación de un constructor de clase base, pero Konrad has given a good answer que bien podría resolver su problema. Sin embargo, esto tiene sus desventajas (por ejemplo, cuando necesita inicializar varias funciones con valores cuyos cálculos comparten resultados intermedios), así que para completar, aquí hay otra forma de resolver el problema del orden de inicialización fijo, por usando .

Dado el orden fijo de inicialización, si tiene control sobre la clase derivada (¿y de qué otro modo podría venir a jugar con uno de sus ctors?), Puede colarse en una base privada por lo que va a ser inicializado antes de la otra base, que luego puede ser inicializado con los valores ya calculados de la base privada:

class my_dirty_little_secret { 
    // friend class the_class; 
public: 
    my_dirty_little_secret(const std::string& str) 
    { 
    // however that calculates x, y, and z from str I wouldn't know 
    } 
    int x; 
    std::string y; 
    float z; 
}; 

class the_class : private my_dirty_little_secret // must be first, see ctor 
       , public the_other_base_class { 
    public: 
    the_class(const std::string str) 
     : my_dirty_little_secret(str) 
     , the_other_base_class(x, y, z) 
    { 
    } 
    // ... 
}; 

La clase my_dirty_little_secret es una base privada por lo que los usuarios de the_class no pueden usarlo, todas sus cosas son privadas, también, con amistad explícita que solo otorga acceso a the_class. Sin embargo, dado que se encuentra primero en la lista de la clase base, se construirá de manera confiable antes de the_other_base_class, por lo que lo que se calcula se puede usar para inicializar eso.
Un buen comentario en la lista de la clase base con suerte evita que otros rompan cosas al refactorizar.

Cuestiones relacionadas