Constructor llama a constructor: cadenas en C++ — ¿es posible?

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

«De un constructor a otro»: la eterna pregunta del desarrollador de C++

\n\n

Imagina la situación: estás escribiendo una clase con varios constructores. Uno acepta tres parámetros, otro dos, otro uno. Y en todos se repite la misma lógica de inicialización. Te pica la mano escribir algo como MyClass() : MyClass(42, "default") {} — y olvidarte de la duplicación. Pero el compilador de C++ (hasta cierto punto) lo mira con recelo. ¿Se puede realmente llamar a un constructor desde otro constructor? Y si es así, ¿cómo?

\n\n

Esta pregunta es una de las más populares en Stack Overflow (decenas de miles de visitas). No es de extrañar: el tema de las cadenas de constructores (constructor chaining) es un verdadero escollo para principiantes e incluso desarrolladores experimentados que migran a C++ desde Java o Python. En este artículo analizaremos tres enfoques para resolver el problema, desde «parches» hasta soluciones elegantes de C++11, y descubriremos cuál vale la pena usar en código real.

\n\n

¿Por qué no se puede simplemente llamar a un constructor desde otro?

\n\n

El enfoque ingenuo se ve así:

\n\n
class MyClass {\npublic:\n    MyClass() {\n        // algún código\n    }\n    MyClass(int x) {\n        MyClass(); // ERROR: ¡no se puede!\n    }\n};
\n\n

En C++, un constructor no es una función normal. Inicializa el objeto una sola vez. Si intentas llamar explícitamente a otro constructor dentro del cuerpo, el compilador lo interpretará como la creación de un objeto temporal — y no se inicializará nada en la instancia actual. Resultado: o un error de compilación o (peor aún) comportamiento indefinido.

\n\n

Antes del estándar C++11, la única forma legal de «compartir» la lógica de inicialización era llamar a un método privado init(). Pero esto no era una verdadera delegación: los miembros de la clase se inicializaban primero con el constructor por defecto y luego se sobrescribían. Ineficiente y propenso a errores.

\n\n

Enfoque n.º 1: constructores delegados (C++11 y posteriores)

\n\n

A partir de C++11, el lenguaje incorporó una función muy esperada: los constructores delegados (delegating constructors). Ahora se puede llamar a un constructor desde otro directamente en la lista de inicialización:

\n\n
class MyClass {\n    int value;\n    std::string name;\npublic:\n    // Constructor base\n    MyClass(int v, const std::string& n) : value(v), name(n) {\n        std::cout << "Full init: " << value << ", " << name << "\\n";\n    }\n    // Constructor delegado\n    MyClass(int v) : MyClass(v, "default") {}\n    // Otro constructor delegado\n    MyClass() : MyClass(0, "default") {}\n};
\n\n

¿Cómo funciona? El constructor MyClass(int v) pasa el control al constructor MyClass(int, string). Este realiza toda la inicialización, y solo después el control regresa. Regla importante: en la lista de inicialización no se puede mezclar la llamada a otro constructor con la inicialización directa de miembros. O delegación o inicialización propia, una de las dos.

\n\n

Ventajas y desventajas

\n
    \n
  • ✅ Elegancia: el código queda limpio, sin duplicación.
  • \n
  • ✅ Rendimiento: el objeto se inicializa una sola vez, sin operaciones innecesarias.
  • \n
  • ⚠️ Limitación: la delegación solo funciona en un solo «nivel»: la cadena no puede ser recursiva (provocarías un desbordamiento de pila).
  • \n
  • ⚠️ Compatibilidad: requiere C++11 o superior. Si estás atascado con un compilador antiguo, esta opción no es para ti.
  • \n
\n\n

Enfoque n.º 2: método privado init()

\n\n

La forma clásica «pre-C++11» es extraer la lógica común a un método privado. Se ve así:

\n\n
class MyClass {\n    int value;\n    std::string name;\n    void init(int v, const std::string& n) {\n        value = v;\n        name = n;\n        std::cout << "Init called\\n";\n                

Blogs

Book Recommendations