[C ++] Hablando del constructor

¿Qué es un constructor?

El constructor es una función que se llama automáticamente a medida que se crea el objeto, y su función principal es inicializar el objeto.

C ++ estipula que la función miembro con el mismo nombre que la clase es el constructor. El constructor debe ser una función miembro pública y el constructor no tiene ningún tipo de valor de retorno.

Los constructores se pueden sobrecargar al igual que las funciones normales.

En C ++, cada clase tiene y debe tener un constructor, si el usuario no escribe un constructor por sí mismo, el compilador proporcionará un constructor sin parámetros, llamado constructor predeterminado.

Pero este constructor predeterminado no realiza ningún trabajo de inicialización. Una vez que el usuario escribe un constructor, el constructor predeterminado sin parámetros desaparece. Si el usuario quiere tener un constructor sin parámetros, debe escribirlo él mismo.

El siguiente es un ejemplo de sobrecarga del constructor:

<span style="font-family:Microsoft YaHei;">#include <iostream>
using namespace std;

class Node
{
public:
	Node();
	//constructors with arguements
	Node(int i, char c = '0');
	Node(int i, char c, Node *p, Node *n);

	int readi() const;
	char readc() const;
	Node * readp() const;
	Node * readn() const;

	bool set(int i);
	bool set(char c);
	bool setp(Node *p);
	bool setn(Node *n);

private:
	int idata;
	char cdata;
	Node *prior;
	Node *next;
};

Node::Node()
{
	cout << "Node constructor is running..."<<endl;
	idata = 0;
	cdata = '0';
	prior = NULL;
	next = NULL;
}

Node::Node(int i, char c)
{
	cout << "Node constructor is running..."<<endl;
	idata = i;
	cdata = c;
	prior = NULL;
	next = NULL;
}

Node::Node(int i, char c, Node *p, Node *n)
{
	cout << "Node constructor is running..."<<endl;
	idata = i;
	cdata = c;
	prior = NULL;
	next = NULL;
}

int Node::readi() const
{
	return idata;
}

char Node::readc() const
{
	return cdata;
}

Node * Node::readp() const
{
	return prior;
}

Node * Node::readn() const
{
	return next;
}

bool Node::set(int i)
{
	idata = i;
	return true;
}

bool Node::set(char c)
{
	cdata = c;
	return true;
}

bool Node::setp(Node *p)
{
	prior = p;
	return true;
}

bool Node::setn(Node *n)
{
	next = n;
	return true;
}
</span>

<span style="font-family:Microsoft YaHei;">#include <iostream>
#include "node.h"
using namespace std;

int main()
{
	Node a; //create an object of Node, call the constructor
	Node b(8);
	Node c(8, 'F', NULL, NULL);
	cout <<a.readi()<<' '<<a.readc() <<endl;
	cout <<b.readi()<<' '<<b.readc() <<endl;
	cout <<c.readi()<<' '<<c.readc() <<endl;
	return 0;
}</span>

resultado:

El constructor de nodo se está ejecutando ... El
constructor de nodo se está ejecutando ... El
constructor de nodo se está ejecutando ...
0 0
8 0
8 F

¿Qué es la lista de inicialización del constructor?

La lista de inicialización del constructor es una lista de miembros de datos separados por un ":" que comienza con ",", y cada dato va seguido de una expresión de inicialización entre paréntesis.

Inicialización explícita cuando se usa la lista de inicialización e inicialización implícita cuando no se usa el constructor de la lista de inicialización.


Ejecución del constructor

La ejecución del constructor se puede dividir en dos fases, la fase de inicialización y la fase de cálculo, la fase de inicialización precede a la fase de cálculo.

Todos los miembros del tipo de clase se inicializarán en la fase de inicialización, incluso si el miembro no aparece en la lista de inicialización del constructor.

/*
 * constructor2.cpp
 *
 *  Created on: 2016年2月20日
 *      Author: chenwei
 */
#include <iostream>
using namespace std;

class Test1
{
public:
	Test1():a(0) //constructor with no arguements
	{
		cout << "Constructor Test1" << endl;
	}
	Test1 (const Test1& t1) //copy constructor
	{
		cout << "Copy constructor for Test1" << endl;
		this->a = t1.a;
	}

	Test1& operator = (const Test1& t1)
	{
		cout << "assignment for Test1" <<endl;
		this->a = t1.a;
		return *this;
	}
private:
	int a;
};

class Test2
{
private:
	Test1 test1;
public:
	Test2(Test1 &t1)
	{
		test1 = t1;
	}
};

int main()
{
	Test1 t1;
	Test2 t2(t1);
	return 1;
}
<strong>
</strong>

resultado:

Constructor Test1 Asignación de
Constructor Test1
para Test1


La primera línea corresponde a Test1 t1 en la función principal, que construye un objeto Test1

La segunda línea corresponde al código en el constructor de la salida Test2. El objeto test1 se inicializa con el constructor predeterminado. Las dos primeras líneas son la llamada fase de inicialización.

La tercera línea corresponde al operador de asignación que genera Test1, que se utiliza para asignar valores entre dos objetos del mismo tipo, y copiar test1.Esta es la llamada fase de cálculo.


¿Cuál es el significado de usar la lista de inicialización y la asignación en el cuerpo del constructor? ¿Cuál es la diferencia entre los dos?

Para los tipos de datos integrados y los tipos compuestos (punteros, referencias), el rendimiento y los resultados de los dos son los mismos.

Para los tipos definidos por el usuario (tipos de clases), el resultado es el mismo, pero hay una gran diferencia en el rendimiento. En el ejemplo anterior, si usa la lista de inicialización, la impresión será diferente:

class Test2
{
private:
	Test1 test1;
public:
	Test2(Test1 &t1):test1(t1) {}
};
resultado:

Constructor Test1
Copiar constructor para Test1

El uso de la lista de inicialización reduce el proceso de llamar al constructor predeterminado una vez, lo cual es muy eficiente para aplicaciones con uso intensivo de datos.


Orden de inicialización de variables miembro

1. Cuando se usa la lista de inicialización para inicializar variables miembro, el orden de inicialización no tiene nada que ver con el orden en el que aparecen en la lista de inicialización, solo el orden en el que se declaran las variables miembro.

Porque el orden de inicialización de las variables miembro se basa en el orden de las variables en la memoria, y el orden de las variables en la memoria se basa en el orden de declaración de las variables.

<span style="font-family:Microsoft YaHei;">#include <iostream>
using namespace std;
class A
{
private:
	int n1;
	int n2;
public:
	A():n2(0), n1(n2+2) {}

	void Print()
	{
		cout << "n1:" << n1 << ", n2: " << n2 << endl;
	}
};

int main()
{
	A a;
	a.Print();
	return 1;
}
</span>

resultado:

n1: 4194434, n2: 0

Dado que n1 se define antes que n2, n1 se inicializará primero, pero en este momento n2 no se inicializa, por lo que el resultado de n1 será un valor aleatorio.


2. Si no se utiliza la lista de inicialización, en su lugar se inicializa en el constructor y el orden de inicialización es coherente con el orden declarado en el constructor .

<span style="font-family:Microsoft YaHei;">	A()
	{
		n2 = 0;
		n1 = n2 +2;
	}</span>
resultado:

n1: 2, n2: 0


3. Los miembros de la clase no se pueden inicializar cuando se declaran.


4. Las variables miembro estáticas de la clase deben inicializarse fuera de la clase.

La secuencia de inicialización de las variables miembro estáticas es que las variables miembro estáticas de la clase base se inicializan primero y luego las variables miembro estáticas de la clase derivada, sabiendo que se inicializan todas las variables miembro estáticas.

Y debido a que las variables estáticas y las variables globales se colocan en el área de la memoria pública, la inicialización de las variables estáticas y las variables globales no está en orden, y las variables estáticas se pueden considerar como variables globales con alcance.

Una vez finalizado todo el trabajo de inicialización, se llamará a la función principal. Si se ejecuta el constructor de una determinada clase, se inicializarán las variables miembro de la clase base. Luego están las variables miembro de la clase derivada.

En resumen, es estático primero, luego común, primero la clase base y luego la clase derivada.


¿Qué tipo de variables miembro deben inicializarse a través de la lista de inicialización?

1 miembros const, los miembros const no se pueden inicializar por asignación, solo a través de la lista de inicialización.

2 & Tipo de referencia, según la definición de la referencia, se debe inicializar cuando se define, y no se puede reasignar, por lo que también se debe inicializar en la lista de inicialización.

3 Un tipo de miembro es una clase sin un constructor predeterminado. Si no se proporciona una lista de inicialización explícita, el compilador usará implícitamente el constructor predeterminado del tipo de miembro. Si no hay un constructor predeterminado, el intento del compilador fallará. A través de la lista de inicialización, puede llamar al constructor de copia en lugar del constructor predeterminado para inicializar.



Supongo que te gusta

Origin blog.csdn.net/michellechouu/article/details/50704224
Recomendado
Clasificación