Levik
¿Cuáles son las reglas de C++ para llamar al constructor de la clase base desde una clase derivada?
Por ejemplo, sé que en Java, debe hacerlo como la primera línea del constructor de la subclase (y si no lo hace, se asume una llamada implícita a un superconstructor sin argumentos, lo que le da un error de compilación si falta) .
lucas
Los constructores de la clase base se llaman automáticamente si no tienen ningún argumento. Si desea llamar a un constructor de superclase con un argumento, debe usar la lista de inicialización del constructor de la subclase. A diferencia de Java, C++ admite la herencia múltiple (para bien o para mal), por lo que se debe hacer referencia a la clase base por su nombre, en lugar de “super()”.
class SuperClass
{
public:
SuperClass(int foo)
{
// do something with foo
}
};
class SubClass : public SuperClass
{
public:
SubClass(int foo, int bar)
: SuperClass(foo) // Call the superclass constructor in the subclass' initialization list.
{
// do something with bar
}
};
Más información sobre la lista de inicialización del constructor. aquí y aquí.
-
Eliminé ‘explícito’ del constructor SuperClass. A pesar de ser una mejor práctica para los constructores de un solo argumento, no estaba relacionado con la discusión en cuestión. Para obtener más información sobre la palabra clave explícita, consulte: weblogs.asp.net/kennykerr/archive/2004/08/31/…
– lucas
24 de septiembre de 2008 a las 12:38
-
el operador de dos puntos: que usó para invocar el constructor de la superclase antes de instanciar el constructor de la clase secundaria, ¿supongo que esto también es cierto para los métodos?
– ha9u63ar
31 de octubre de 2014 a las 9:33
-
@hagubear, solo válido para constructores, AFAIK
– lucas
31 de octubre de 2014 a las 12:24
-
Cuando crea una instancia de un objeto SubClass, por ejemplo,
SubClass anObject(1,2)
lo hace1
luego pasar aSuperClass(foo)
(se convierte en el argumento de paramaterfoo
)? He estado buscando en documentos altos y bajos, pero ninguno afirma definitivamente que los argumentos del constructor SubClass se pueden pasar como argumentos al constructor SuperClass.– LazerSharks
24 de noviembre de 2014 a las 1:49
-
@Gnuey, observe el
: SuperClass(foo)
parte.foo
se pasa explícitamente al constructor de la superclase.– lucas
24 de noviembre de 2014 a las 2:27
puetzk
En C++, los constructores sin argumentos para todas las superclases y variables miembro se llaman por usted, antes de ingresar su constructor. Si desea pasarles argumentos, hay una sintaxis separada para esto llamada “encadenamiento de constructores”, que se ve así:
class Sub : public Base
{
Sub(int x, int y)
: Base(x), member(y)
{
}
Type member;
};
Si algo ejecutado en este punto arroja, las bases/miembros que habían completado previamente la construcción tienen sus destructores llamados y la excepción se vuelve a lanzar a la persona que llamó. Si desea detectar excepciones durante el encadenamiento, debe usar un bloque de prueba de función:
class Sub : public Base
{
Sub(int x, int y)
try : Base(x), member(y)
{
// function body goes here
} catch(const ExceptionType &e) {
throw kaboom();
}
Type member;
};
En este formulario, tenga en cuenta que el bloque try es el cuerpo de la función, en lugar de estar dentro del cuerpo de la función; esto le permite detectar excepciones lanzadas por miembros implícitos o explícitos e inicializaciones de clase base, así como durante el cuerpo de la función. Sin embargo, si un bloque catch de función no arroja una excepción diferente, el tiempo de ejecución volverá a generar el error original; excepciones durante la inicialización no poder ser ignorado.
-
No estoy seguro de entender la sintaxis de su segundo ejemplo… ¿Es la construcción try/catch un reemplazo para el cuerpo del constructor?
– Levik
23 de septiembre de 2008 a las 13:47
-
Si. Reformulé la sección y solucioné un error (la palabra clave de prueba va antes de la lista de inicialización). Debería haberlo buscado en lugar de escribir de memoria, no es algo que se use a menudo 🙂
– puetzk
23 de septiembre de 2008 a las 15:55
-
Gracias por incluir la sintaxis try/catch para los inicializadores. He estado usando C++ durante 10 años, y esta es la primera vez que lo veo.
– jakar
8 de junio de 2012 a las 17:23
-
Debo admitir que he estado usando C ++ durante mucho tiempo, y esa es la primera vez que veo que try/catcn en la lista de constructores.
– Cameron
21 de noviembre de 2013 a las 1:29
-
Podría decir que el cuerpo de la función “entra” en el bloque de prueba; de esta manera, cualquier cuerpo que siga a los inicializadores también tendrá sus excepciones detectadas.
– peterk
16 de enero de 2019 a las 15:28
En C++ hay un concepto de lista de inicialización del constructor, que es donde puede y debe llamar al constructor de la clase base y donde también debe inicializar los miembros de datos. La lista de inicialización viene después de la firma del constructor después de dos puntos y antes del cuerpo del constructor. Digamos que tenemos una clase A:
class A : public B
{
public:
A(int a, int b, int c);
private:
int b_, c_;
};
Entonces, asumiendo que B tiene un constructor que toma un int, el constructor de A puede verse así:
A::A(int a, int b, int c)
: B(a), b_(b), c_(c) // initialization list
{
// do something
}
Como puede ver, el constructor de la clase base se llama en la lista de inicialización. Por cierto, es preferible inicializar los miembros de datos en la lista de inicialización que asignar los valores para b_ y c_ dentro del cuerpo del constructor, porque se está ahorrando el costo adicional de la asignación.
Tenga en cuenta que los miembros de datos siempre se inicializan en el orden en que se declaran en la definición de clase, independientemente de su orden en la lista de inicialización. Para evitar errores extraños, que pueden surgir si sus miembros de datos dependen unos de otros, siempre debe asegurarse de que el orden de los miembros sea el mismo en la lista de inicialización y en la definición de clase. Por la misma razón, el constructor de la clase base debe ser el primer elemento de la lista de inicialización. Si lo omite por completo, se llamará automáticamente al constructor predeterminado para la clase base. En ese caso, si la clase base no tiene un constructor predeterminado, obtendrá un error de compilación.
-
Espera un segundo… Dices que los inicializadores ahorran en el costo de las asignaciones. Pero, ¿no tienen lugar dentro de ellos las mismas asignaciones si son llamados?
– Levik
23 de septiembre de 2008 a las 13:39
-
No. Init y asignación son cosas diferentes. Cuando se llama a un constructor, intentará inicializar cada miembro de datos con lo que crea que es el valor predeterminado. En la lista de inicio, puede proporcionar valores predeterminados. Por lo tanto, incurre en costos de inicialización en cualquier caso.
– Dima
23 de septiembre de 2008 a las 13:44
-
Y si usa la asignación dentro del cuerpo, entonces incurre en el costo de inicialización de todos modos, y luego el costo de la asignación además de eso.
– Dima
23 de septiembre de 2008 a las 13:44
-
Esta respuesta fue útil porque mostró la variante de sintaxis donde uno tiene un encabezado y un archivo fuente, y uno no quiere la lista de inicialización en el encabezado. Muy útil gracias
– Benjamín
11 de noviembre de 2014 a las 17:17
TT_
Todos mencionaron una llamada de constructor a través de una lista de inicialización, pero nadie dijo que el constructor de una clase principal se puede llamar explícitamente desde el cuerpo del constructor del miembro derivado. Consulte la pregunta Llamar a un constructor de la clase base desde el cuerpo del constructor de una subclase, por ejemplo. El punto es que si usa una llamada explícita a una clase principal o un constructor de superclase en el cuerpo de una clase derivada, esto en realidad solo está creando una instancia de la clase principal y no está invocando al constructor de la clase principal en el objeto derivado. . La única forma de invocar una clase principal o un constructor de superclase en un objeto de clase derivada es a través de la lista de inicialización y no en el cuerpo del constructor de la clase derivada. Entonces, tal vez no debería llamarse “llamada al constructor de superclase”. Pongo esta respuesta aquí porque alguien podría confundirse (como yo).
Nils Pipenbrinck
Si tiene un constructor sin argumentos, se llamará antes de que se ejecute el constructor de la clase derivada.
Si desea llamar a un constructor base con argumentos, debe escribirlo explícitamente en el constructor derivado de esta manera:
class base
{
public:
base (int arg)
{
}
};
class derived : public base
{
public:
derived () : base (number)
{
}
};
No puede construir una clase derivada sin llamar al constructor principal en C++. Eso sucede automáticamente si es un C’tor que no es un argumento, sucede si llama al constructor derivado directamente como se muestra arriba o su código no se compilará.
La única forma de pasar valores a un constructor principal es a través de una lista de inicialización. La lista de inicialización se implementa con un : y luego una lista de clases y los valores que se pasarán a ese constructor de clases.
Class2::Class2(string id) : Class1(id) {
....
}
También recuerde que si tiene un constructor que no toma parámetros en la clase principal, se llamará automáticamente antes de que se ejecute el constructor secundario.
edw
Si tiene parámetros predeterminados en su constructor base, la clase base se llamará automáticamente.
using namespace std;
class Base
{
public:
Base(int a=1) : _a(a) {}
protected:
int _a;
};
class Derived : public Base
{
public:
Derived() {}
void printit() { cout << _a << endl; }
};
int main()
{
Derived d;
d.printit();
return 0;
}
La salida es: 1
-
Esto es solo porque esa declaración en particular crea un implícito
Base()
que tiene el mismo cuerpo queBase(int)
pero más un inicializador implícito para: _a{1}
. EsBase()
que siempre se llama si no hay un constructor base específico encadenado en la lista de inicio. Y, como se mencionó en otra parte, los constructores de delegación de C++ 11 y la inicialización de llaves o iguales hacen que los argumentos predeterminados sean bastante menos necesarios (cuando ya eran código-smell-esque en muchos ejemplos).– subrayado_d
10 de febrero de 2016 a las 23:21
Simplemente quisquilloso: no hay una “superclase” en C ++, de hecho, el estándar no lo menciona en absoluto. Esta redacción proviene de Java (muy probablemente). Use “clase base” en C++. Supongo súper implica un único padre, mientras que C++ permite la herencia múltiple.
– andreee
11 de junio de 2018 a las 12:44
@andreee lo enrojecí
super class
es tambien llamadobase class
y también fe en el kit de herramientas qtparent class
– en ese orden unsub class
es tambien llamadochild class
Tal vez eso ayude a combatir una posible confusión en la terminología.– Ingo Mi
15 de junio de 2020 a las 14:31