Cómo aprobar una entrevista de C++: las mejores preguntas de nivel avanzado
\n\nLa entrevista para un puesto de desarrollador C++ de nivel medio y senior no es solo una verificación de sintaxis. Los entrevistadores quieren ver una comprensión profunda del funcionamiento interno del lenguaje, la capacidad de trabajar con memoria, plantillas y concurrencia. En este artículo, analizamos las preguntas más frecuentes y difíciles que se hacen en las entrevistas de C++ de nivel avanzado. Cada pregunta va acompañada de una explicación y un ejemplo de código.
\n\n1. Punteros inteligentes y RAII
\n\nLa pregunta sobre punteros inteligentes es un clásico. Se espera que no solo menciones std::unique_ptr, std::shared_ptr y std::weak_ptr, sino que también expliques su funcionamiento interno y cuándo usar cada uno.
Pregunta típica: ¿Cuál es la diferencia entre unique_ptr y shared_ptr? ¿Cómo funciona el contador de referencias en shared_ptr? ¿Para qué sirve weak_ptr?
Respuesta: std::unique_ptr es una propiedad exclusiva de un recurso. No se puede copiar, solo mover (semántica de movimiento). std::shared_ptr utiliza un conteo de referencias (reference counting) para la propiedad compartida. Cuando el contador llega a cero, el objeto se elimina. std::weak_ptr es un "observador" que no incrementa el contador de referencias. Se utiliza para prevenir dependencias cíclicas (por ejemplo, en grafos o árboles).
#include <memory>\n#include <iostream>\n\nstruct Resource {\n Resource() { std::cout << "Resource acquired\\n"; }\n ~Resource() { std::cout << "Resource released\\n"; }\n};\n\nint main() {\n // unique_ptr\n std::unique_ptr<Resource> ptr1 = std::make_unique<Resource>();\n // std::unique_ptr<Resource> ptr2 = ptr1; // Error de compilación - copia prohibida\n std::unique_ptr<Resource> ptr2 = std::move(ptr1); // Movimiento permitido\n\n // shared_ptr\n std::shared_ptr<Resource> sptr1 = std::make_shared<Resource>();\n std::shared_ptr<Resource> sptr2 = sptr1; // Copia permitida, contador = 2\n\n // weak_ptr\n std::weak_ptr<Resource> wptr = sptr1; // El contador no aumenta\n if (auto locked = wptr.lock()) {\n std::cout << "Resource is still alive\\n";\n }\n\n return 0;\n}\n\nPregunta adicional: ¿Cómo implementarías tu propio SharedPtr? Aquí es importante mencionar RAII (Resource Acquisition Is Initialization) — el principio por el cual la adquisición de un recurso ocurre en el constructor y la liberación en el destructor.
2. Destructores virtuales y tabla de funciones virtuales (vtable)
\n\nEsta pregunta evalúa la comprensión del polimorfismo y el funcionamiento de las funciones virtuales en C++.
\n\nPregunta típica: ¿Por qué en una clase base con funciones virtuales debe haber un destructor virtual? ¿Cómo funciona la vtable?
\n\nRespuesta: Si el destructor de la clase base no es virtual, al eliminar un objeto de una clase derivada a través de un puntero a la clase base, solo se llamará al destructor de la clase base. Esto provocará una fuga de los recursos que asignó la clase derivada.
\n\nCada clase que tiene al menos una función virtual contiene una tabla estática (vtable). En ella se almacenan punteros a las implementaciones de las funciones virtuales. Cada objeto de dicha clase tiene un puntero oculto (vptr) que apunta a la vtable de su clase. La llamada a una función virtual se realiza mediante una doble indirección: objeto → vptr → vtable → función. Esto añade una pequeña sobrecarga en comparación con una llamada normal.
\n\n#include <iostream>\n\nclass Base {\npublic:\n virtual void show() { std::cout << "Base\\n"; }\n virtual ~Base() = default; // Destructor virtual\n};\n\nclass Derived : public Base {\npublic:\n void show() override { std::cout << "Deriv