La función predeterminada en C ++ 11

Para la función predeterminada admitida en el estándar C ++ 11 , el compilador generará automáticamente un cuerpo de definición de función predeterminada para ella, a fin de obtener una mayor eficiencia de ejecución de código, y también puede salvar al programador de la carga de trabajo de definir manualmente la función.

Las clases de C ++ tienen cuatro tipos de funciones miembro especiales, son:

  • Constructor predeterminado
  • Incinerador de basuras
  • Copiar constructor
  • Operador de asignación de copia

Las funciones miembro especiales de estas clases son responsables de crear, inicializar, destruir o copiar objetos de la clase. Si el programador no define explícitamente una función miembro especial para una clase, y la función miembro especial necesita ser utilizada, el compilador Generará implícitamente una función miembro especial predeterminada para esta clase. P.ej:

Listado 1

class X{
    
    
private:
	int a;
};

X x;

En el Listado 1, el programador no define el constructor predeterminado de la clase X, pero al crear un objeto x de la clase X, se debe usar el constructor predeterminado de la clase X. En este momento, el compilador se referirá implícitamente a la clase X genera un constructor predeterminado. El constructor predeterminado generado automáticamente no tiene parámetros y contiene un cuerpo de función vacío, a saber, X :: X () {}. Aunque el constructor predeterminado generado automáticamente solo tiene un cuerpo de función vacío, aún se puede usar para crear exitosamente un objeto x de clase X. El Listado 1 también se puede compilar.

Sin embargo, si el programador personaliza explícitamente un constructor no predeterminado para la clase X, pero no define el constructor predeterminado, aparecerá un error de compilación en el Listado 2:

Listado 2

class X{
    
    
public:
	X(int i){
    
    
	a = i;
	}
private:
	int a;
};

X x; // 错误 , 默认构造函数 X::X() 不存在

La razón del error de compilación en el Listado 2 es que la clase X ya tiene un constructor definido por el usuario, por lo que el compilador ya no generará implícitamente un constructor predeterminado para él. Si necesita utilizar el constructor predeterminado para crear objetos de la clase, el programador debe definir explícitamente el constructor predeterminado. P.ej:

Listado 3

class X{
    
    
	public:
	X(){
    
    }; // 手动定义默认构造函数
	X(int i){
    
    
	a = i;
	}
	private:
	int a;
};

X x; // 正确,默认构造函数 X::X() 存在

Como puede verse en el Listado 3, el constructor predeterminado que originalmente se esperaba que el compilador generara automáticamente debe ser escrito manualmente por el programador, es decir, la carga de trabajo del programador ha aumentado. Además, la eficiencia de ejecución de código del constructor predeterminado escrito manualmente es menor que la del constructor predeterminado generado automáticamente por el compilador. Los otros tipos de funciones miembro especiales de la clase también son los mismos que los del constructor predeterminado. Cuando hay funciones miembros especiales definidas por el usuario, el compilador no generará implícitamente automáticamente las funciones miembro especiales predeterminadas. En su lugar, los programadores deben escribirlas manualmente. Se reduce la carga de trabajo del programador. De manera similar, la eficiencia de ejecución de código de la función miembro especial escrita manualmente es menor que la de la función miembro especial generada automáticamente por el compilador.

Para resolver los dos problemas que se muestran en el Listado 3:

  1. Reducir la carga de trabajo de programación del programador;
  2. Obtenga una alta eficiencia de ejecución de código de la función miembro especial predeterminada generada automáticamente por el compilador

El estándar C ++ 11 introdujo una nueva característica: la función predeterminada . El programador puede declarar =default;la función como una función predeterminada simplemente agregándola después de la declaración de la función, y el compilador generará automáticamente el cuerpo de la función para la función predeterminada declarada explícitamente. P.ej:

Listado 4

class X{
    
    
public:
	X()= default;
	X(int i){
    
    
	a = i;
}
private:
	int a;
};

X x;

En el Listado 4, el compilador generará automáticamente el constructor predeterminado X :: X () {}, que puede lograr una mayor eficiencia de código que el constructor predeterminado definido por el usuario.

La función de función predeterminada solo se aplica a la función de miembro especial de la clase, y la función de miembro especial no tiene parámetros predeterminados . P.ej:

Listado 5

class X {
    
    
public:
	int f() = default; // 错误 , 函数 f() 非类 X 的特殊成员函数
	X(int) = default; // 错误 , 构造函数 X(int, int) 非 X 的特殊成员函数
	X(int = 1) = default; // 错误 , 默认构造函数 X(int=1) 含有默认参数
};

La función predeterminada se puede definir en el cuerpo de la clase (en línea) o fuera de la clase (fuera de línea). P.ej:

Listado 6

class X{
    
    
public:
	X() = default; //Inline default 默认构造函数
	X(const X&);
	X& operator = (const X&);
	~X() = default; //Inline default 析构函数
};

X::X(const X&) = default; //Out-of-line default 拷贝构造函数
X& X::operator = (const X&) = default; //Out-of-line default
// 拷贝赋值操作符

En el proceso de compilación de código C ++, si el programador no define un destructor para la clase X, pero necesita llamar al destructor de la clase X al destruir el objeto de la clase X, el compilador generará automática e implícitamente un destructor para la clase Destructor. El destructor generado automáticamente no tiene parámetros y contiene un cuerpo de función vacío, a saber, X :: ~ X () {}. P.ej:

Listado 7

class X {
    
    
private:
	int x;
};

class Y: public X {
    
    
private:
	int y;
};

int main(){
    
    
	X* x = new Y;
	delete x;
}

En el Listado 7, el programador no definió un destructor para la clase base X y la clase derivada Y. Cuando se elimina el puntero de la clase base x en la función principal, es necesario llamar al destructor de la clase base. Por lo tanto, el compilador generará implícita y automáticamente un destructor para la clase X, de modo que pueda destruir con éxito el subobjeto de la clase base (es decir, la variable miembro de tipo int x) en el objeto de la clase derivada apuntado por x.

Sin embargo, este código tiene un problema de pérdida de memoria. Cuando se usa la instrucción delete para eliminar el puntero x al objeto de la clase derivada, el sistema llama al destructor de la clase base en lugar del destructor de la clase derivada Y. Por lo tanto, compile el dispositivo no se puede deconstruir la variable y miembro de tipo int de la clase derivada.

Por lo tanto, en circunstancias normales, necesitamos definir el destructor de la clase base como una función virtual.Cuando la declaración de eliminación se usa para eliminar el puntero de la clase base al objeto de la clase derivada, el sistema llamará al destructor correspondiente de la clase derivada. (para lograr polimorfismo) Para evitar pérdidas de memoria. Sin embargo, los destructores generados implícita y automáticamente por el compilador son todas funciones no virtuales, lo que requiere que el programador defina manualmente un destructor virtual para la clase base X, por ejemplo:

Listado 8

class X {
    
    
public:
	virtual ~X(){
    
    }; // 手动定义虚析构函数
private:
	int x;
};

class Y: public X {
    
    
private:
	int y;
};

int main(){
    
    
	X* x = new Y;
	delete x;
}

En el Listado 8, dado que el programador definió manualmente el destructor virtual para la clase base X, cuando la declaración de eliminación se usa para eliminar el puntero de la clase base x que apunta al objeto de la clase derivada, el sistema llamará a la función destructora correspondiente de la clase derivada. Y (por El compilador genera implícitamente automáticamente) y el destructor de la clase base X, destruyendo así por completo el objeto de la clase derivada, lo que puede evitar pérdidas de memoria.

Sin embargo, en el Listado 8, el programador necesita escribir manualmente la definición de la función virtual de la clase base (incluso si el cuerpo de la función está vacío), lo que aumenta la carga de trabajo de programación del programador. Lo que es más digno de mención es que la eficiencia de ejecución de código del destructor definido manualmente es menor que la del destructor generado automáticamente por el compilador.

Para resolver los problemas anteriores, podemos declarar el destructor virtual de la clase base como la función predeterminada , de modo que el compilador pueda especificarse explícitamente para generar automáticamente el cuerpo de la función. P.ej:

Listado 9

class X {
    
    
public:
	virtual ~X()= default; // 编译器自动生成 default 函数定义体
private:
	int x;
};

class Y: public X {
    
    
private:
	int y;
};

int main(){
    
    
	X* x = new Y;
	delete x;
}

En el Listado 9, el compilador genera automáticamente un destructor virtual virtual X::X(){}, que tiene una mayor eficiencia de ejecución de código que el destructor virtual definido por el usuario.

Supongo que te gusta

Origin blog.csdn.net/u013318019/article/details/113894153
Recomendado
Clasificación