2011-09-08 10 views
26

Mi comprensión del encadenamiento de constructores es que, cuando hay más de un constructor en una clase (constructores sobrecargados), si uno de ellos intenta llamar a otro constructor, entonces este proceso se llama CONSTRUCTOR CHAINING, que no es compatible con C++. Recientemente me encontré con este párrafo, mientras que la lectura de material en línea .... Dice así ...Cadena de constructor en C++

Usted puede encontrarse en la situación en la que desea escribir una función miembro para volver a inicializar una clase de nuevo a los valores predeterminados. Como probablemente ya tiene un constructor que hace esto, puede sentirse tentado de intentar llamar al constructor desde su función de miembro. Como se mencionó, encadenar llamadas de constructor son ilegales en C++. Podría copiar el código del constructor en su función, lo que funcionaría, pero conduciría a un código duplicado. La mejor solución en este caso es mover el código del constructor a su nueva función y hacer que el constructor llame a su función para hacer el trabajo de inicialización de los datos.

¿Una función de miembro que llama al constructor también viene bajo encadenamiento de constructor? Por favor, arroje algo de luz sobre este tema en C++.

+3

Yo diría que no, y no es apropiado para el artículo decir que el encadenamiento de constructores es ilegal, inmediatamente después de decir que alguna función miembro arbitraria (no necesariamente un constructor) podría pensar que quiere llamar a un constructor para reiniciar el valor. Pero quién sabe, no ha citado el artículo ni ha citado dónde describe el encadenamiento de constructores, por lo que tal vez lo esté usando en algún sentido inusual ya descrito en otro lugar. –

+1

No es ilegal. Llamar a un constructor desde un miembro tiene el efecto de crear un objeto temporal al que se aplica la construcción, no el objeto 'este' desde el que realiza la llamada. –

+1

@Amardeep: de acuerdo, sería más exacto decir que el encadenamiento de constructores es "imposible" en C++ 03, en lugar de "ilegal". Simplemente no hay sintaxis para describir hacerlo. Como dices, por la definición normal, llamar a un constructor no es en absoluto lo mismo que el encadenamiento del constructor. –

Respuesta

17

El párrafo dice básicamente esto:

class X 
{ 
    void Init(params) {/*common initing code here*/ } 
    X(params1) { Init(someParams); /*custom code*/ } 
    X(params2) { Init(someOtherParams); /*custom code*/ } 
}; 

no puede llamar a un constructor de una función miembro tampoco. Puede parecer que tú has hecho, pero eso es una ilusión:

class X 
{ 
public: 
    X(int i):i(i){} 
    void f() 
    { 
     X(3); //this just creates a temprorary - doesn't call the ctor on this instance 
    } 
    int i; 
}; 

int main() 
{ 
    using std::cout; 
    X x(4); 
    cout << x.i << "\n"; //prints 4 
    x.f(); 
    cout << x.i << "\n"; //prints 4 again 
} 
+0

@ Armen ... Te refieres a la primera vez que está imprimiendo un 4, en realidad está llamando al constructor, y la segunda vez cuando imprime 4, aunque siento como si hubiera logrado el resultado llamando al constructor (desde la función vacía f()), lo que EXACTAMENTE está sucediendo no es eso ... !!! Lo es ?? Pero no entendí tu primer comentario en el código anterior // esto solo crea un temporal - no llama al ctor en esta instancia. ¿Podrías explicarme un poco más claro? – jsp99

+0

Esto ha cambiado con C++ 11, ver http://stackoverflow.com/a/33275207/1915854 –

3

Eso no es lo que dice el texto. Está sugiriendo que su constructor llame a una función miembro que es normal y legal. Esto es para evitar llamar explícitamente al ctor nuevamente y evitar la duplicación de código entre su ctor y la función de reinicio.

Foo::Foo() { 
    Init(); 
} 

void Foo::Reset() { 
    Init(); 
} 

void Foo::Init() { 
    // ... do stuff ... 
} 
+0

Es cierto que el texto no recomienda que la función llama al constructor, sin embargo, el texto dice "puedes tentarte a intentar llamar al constructor desde tu función de miembro. Como se mencionó, encadenar llamadas de constructor es ilegal en C++". Esto sugiere que a través de algunas confusiones de ideas, el autor pensó que "encadenar llamadas de constructor" tiene algo que ver con "llamar al constructor desde su función de miembro", independientemente de si el artículo recomienda hacerlo o no. Podría ser una edición dudosa, por supuesto. –

+0

"Debido a que probablemente ya tengas un constructor que hace esto, puedes tentarte a intentar llamar al constructor desde tu función de miembro". Pensé que esto significaba que UNA FUNCIÓN DE MIEMBRO LLAMANDO A UN CONSTRUCTOR debería evitarse ... !! ?? – jsp99

+0

@Appy: no necesariamente. Por ejemplo, en una clase llamada 'Foo'' * this = Foo(); 'podría ser una forma perfectamente razonable de restablecer el objeto, si no necesariamente el más eficiente. Entonces la función llama al constructor, simplemente no lo llama para construir 'this'. –

0

no estoy seguro de si (llamando a un constructor de una función miembro) funcionará o no, pero es una mala práctica. mover el código de inicialización a una nueva función es la forma lógica.

Básicamente diciendo: No llama al constructor a menos que la construcción ...

+0

No es solo una mala práctica ... No puede funcionar. – Johnsyweb

+0

Estoy de acuerdo con Johnsyweb. Llamar a un constructor desde otro simplemente creará una variable local temporal dentro de él y lo eliminará una vez que el constructor salga. El objeto 'this' no se ve afectado por nada de eso. La única manera de hacerlo es una ubicación nueva y las preguntas frecuentes de C++ repiten muchas veces que es algo horrible de hacer. – MasterMastic

1

cuando llamamos el constructor de una función miembro, entonces se creará un objeto temporal de su tipo. en caso de que llamemos a la función de clase derivada, todos los constructores padre también se ejecutarán y destruirán usando destructor una vez que la función se salga del alcance.

no es una buena práctica para llamar a los constructores en las funciones miembro, ya que crea objetos de todas las clases derivadas.

15

C++ 11 permite el encadenamiento del constructor (parcialmente). Esta función se llama "delegating constructors". Así que en C++ 11 se puede hacer lo siguiente

class Foo 
{ 
public: 
    Foo(int a) : Foo() { _a = a; } 
    Foo(char* b) : Foo() { _b = b; } 
    Foo() { _c = 1.5; } 
private: 
    int _a = 0; 
    char* _b = nullptr; 
    double _c; 
}; 

Sin embargo, hay una limitación grave que un constructor que llama a otro constructor no se le permite inicializar los otros miembros. Por lo que no puede hacer lo siguiente con un constructor delegar:

class Foo 
{ 
public: 
    Foo(int a) : Foo(), _a(a) { } 
    Foo(char* b) : Foo(), _b(b) { } 
    Foo() { _c = 1.5; } 
private: 
    int _a = 0; 
    char* _b = nullptr; 
    double _c; 
}; 

MSVC++ 2013 da compilar error "C3511: una llamada a un constructor delegar será el único miembro-inicializador" para el ejemplo de código de este último.