c ¿Qué es un constructor y cuál es su función?
Explicación detallada del constructor de la clase c
1. ¿Qué hace el constructor?
Contador de clase
{
public:
// Constructor de la clase Counter
// Características: utiliza el nombre de la clase como nombre de la función, sin tipo de retorno
Counter()< / p>
{
m_value = 0
}
privado:
// miembro de datos
int m_value;
}
Cuando se crea este objeto de clase, el objeto del sistema de compilación asigna espacio de memoria y llama automáticamente al constructor -gt; Trabajo
por ejemplo: Contador c1;
El sistema de compilación asigna espacio de memoria para cada miembro de datos (m_value) del objeto c1 y llama al constructor Counter() para inicializar automáticamente el objeto c1. El valor de m_value se establece en 0
Entonces:
La función del constructor: inicializa los miembros de datos del objeto.
2. Tipos de constructores
clase Complejo
{
privado:
doble m_real;
p>
double m_imag;
public:
// Constructor sin parámetros
// Si creas una clase no escribes ningún constructor, el el sistema generará automáticamente un constructor predeterminado sin argumentos, la función está vacía y no hace nada
// Siempre que escriba uno de los siguientes constructores, el sistema ya no generará automáticamente dicho constructor predeterminado , si desea tener un constructor sin argumentos, debe escribirlo explícitamente usted mismo
Complex(void)
{
m_real = 0.0;
m_imag = 0.0;
}
// Constructor general (también llamado constructor sobrecargado)
// Los constructores generales pueden tener varios formas de parámetros, y una clase puede tener múltiples constructores generales, siempre que el número o tipo de parámetros sean diferentes (según el principio de función sobrecargada de c)
// Por ejemplo: también puedes escribir un constructor para Complex(int num)
// Al crear un objeto, llame a diferentes constructores según los parámetros pasados en
Complex(double real, double imag)
{
m_real = real;
m_imag = imag;
}
// Copiar constructor (también llamado copiar constructor) )
// El parámetro del constructor de copia es una referencia al objeto de clase en sí, que se utiliza para copiar un nuevo objeto de la clase basado en un objeto existente. Generalmente, en la función, el valor de la. El miembro de datos del objeto existente se copiará al objeto recién creado
// Si no hay un constructor de copia de escritura explícito, el sistema creará un constructor de copia de forma predeterminada. Sin embargo, cuando hay miembros de puntero. la clase, existe el riesgo de que el sistema cree el constructor de copia de forma predeterminada. Por motivos específicos, consulte los artículos sobre "copia superficial" y "copia profunda"
Complex(const Complex amp). ; c)
{
// Copiar el valor del miembro de datos en el objeto c
m_real = c.m_real;
m_img = c.m_img;
}
// Constructor de conversión de tipo, crea un objeto de esta clase basado en un objeto de un tipo específico
// Por ejemplo : Lo siguiente crea un objeto Complejo basado en un objeto de tipo doble
Complejo:: Complejo(doble r)
{
m_real = r
m_imag = 0.0;
// Sobrecarga del operador de signo igual
// Tenga en cuenta que esto es similar a un constructor de copia, copiando el valor del objeto de esta clase en el lado derecho de = al objeto en el El lado izquierdo del signo igual no pertenece al constructor, etc. Los objetos en los lados izquierdo y derecho del número deben haber sido creados
// Si no hay una sobrecarga explícita del operador write =. , el sistema también creará una sobrecarga de operador = predeterminada y solo realizará algunos trabajos de copia básicos
Complex amp operator=( const Complex amp; rhs )
{
// Primero verifique si el objeto en el lado derecho del signo igual es el objeto en la izquierda. Si es el objeto en sí, luego regrese directamente
if ( this == amp; rhs )
{
return *this;
}
// Copia el miembro en el lado derecho del signo igual al objeto. a la izquierda
this-gt; m_real = rhs.m_real;
this-gt; m_imag = rhs.m_imag
// Genera el objeto en el lado izquierdo del signo igual nuevamente
// El propósito es soportar la ecualización continua, por ejemplo: a=b=c El sistema ejecuta b=c primero
// Luego ejecuta a = (el valor de retorno de b=c, este debería ser el objeto b después de copiar el valor de c)
return *this;
A continuación se utiliza el objeto de clase definido anteriormente para ilustrar el uso de cada constructor:
void main()
{
/ / Se llama al constructor sin parámetros y el valor inicial del miembro de datos se asigna a 0.0
Complex c1, c2
// Se llama al constructor general y al miembro de datos. se inicializa El valor se asigna al valor especificado
Complejo c3(1.0, 2.5);
// También se puede utilizar el siguiente formulario
Complejo c3 = Complex(1.0, 2.5);
// Asigna el valor del miembro de datos de c3 a c1
// Dado que c1 se creó de antemano, no se llamará a ningún constructor. aquí
// Solo se llamará la función sobrecargada del operador =
c1 = c3
// Se llamará el constructor de conversión de tipo
;// El sistema primero llama al constructor de conversión de tipos para crear 5.2 como un objeto temporal de esta clase, y luego llama a la sobrecarga del operador igual para asignar el objeto temporal a c1
c2 = 5.2
;// Llama al constructor de copia (hay dos métodos de llamada a continuación)
Complex c5(c2);
Complex c4 = c2; los operadores y =, el objeto en el lado izquierdo del signo igual aquí no se ha creado de antemano, por lo que es necesario llamar al constructor de copia, el parámetro es c2
}
3. Pensamientos y pruebas
1. Observe atentamente el constructor de copias
Complex(const Complex amp; c)
{
. // Copiar los valores de los miembros de datos en el objeto c
p>m_real = c.m_real
m_img = c.m_img
}
¿Por qué se puede acceder directamente a los miembros privados del objeto c en una función?
2. Preguntas de desafío para comprender la diferencia entre referencia y transferencia de valor
Prueba compleja1(const Complexamp; c)
{
return c;
}
Prueba compleja2(const Complex c)
{
return c; }
Prueba3()
{
Complejo estático c(1.0, 5.0);
return c;
}
Complexamp; test4()
{
Complejo estático c(1.0, 5.0);
return c;
}
void main()
{
Complejo a, b
// Lo siguiente; se ejecuta la función ¿Cuántas veces se llamará al constructor durante el proceso? ¿A qué constructor se llama?
prueba1(a);
prueba2(a);
b = prueba3()
b = prueba4();
test2(1.2);
// ¿Saldrá mal la siguiente declaración?
prueba1(1.2); //prueba1(Complejo(1.2))?
}
IV.Apéndice (Copia superficial y copia profunda)
Como se mencionó anteriormente, si no hay un constructor de copia personalizado, el sistema creará uno predeterminado. constructor de copia, pero el constructor de copia predeterminado creado por el sistema solo realizará una "copia superficial" y se copiará
Los valores de los miembros de datos del objeto Shell se asignan al objeto recién creado uno por uno. Si hay miembros punteros en los miembros de datos de la clase, la dirección apuntada por el puntero del nuevo objeto será la misma. como la dirección señalada por el puntero del objeto copiado, eliminar el puntero provocará dos eliminaciones repetidas y un error.
A continuación se muestra un ejemplo:
Copia superficial y copia profunda
#include lt;iostream.hgt;
#include lt;string.hgt;
clase Persona
{
público:
// Constructor
Persona(char * pN)
{
cout lt; "¡Se llama al constructor general!\n"
m_pName = new char[strlen(pN) 1]; p> //Abre un bloque de memoria en el montón para almacenar la cadena apuntada por pN
if(m_pName != NULL)
{
// Si m_pName no es un puntero nulo, copie la cadena a la que apunta el puntero del parámetro formal pN
strcpy(m_pName, pN);
}
}
// El constructor de copia predeterminado creado por el sistema, solo copia el patrón de bits
Person(Person amp; p)
{
//Hacer que los dos punteros de cadena apunten a la misma ubicación de dirección
m_pName = p.m_pName
}
~Person( ) p>
{
eliminar m_pName
}
privado:
char * m_pName
};
void main()
{
Persona hombre("lujun");
Persona mujer(hombre);
// Como resultado, los punteros de hombre y mujer apuntan a la misma dirección
// Cuando se destruye la función
// Lo mismo la dirección se elimina dos veces
}
// A continuación, diseñe un constructor de copia para implementar una "copia profunda", es decir, no permitir que el puntero apunte a la misma dirección, sino volver a eliminarla. aplicar un trozo de memoria para los datos del puntero del nuevo objeto Member
Person(Person amp; chs);
{
// Usar operador nuevo para asigne espacio para el miembro de datos del puntero del nuevo objeto
m_pName=new char[strlen(p.m_pName) 1];
if(m_pName)
{
// Copiar contenido
strcpy(m_pName , chs.m_pName
}
); // Entonces el m_pName del objeto recién creado y el m_pName del objeto original chs ya no apuntan a la misma dirección
}