¿Qué es una función predeterminada?
La declaración de función explícitamente predeterminada es una nueva forma de declaración de función que se introduce en el estándar C++ 11 que le permite agregar ‘=default;’ especificador al final de una declaración de función para declarar esa función como una función explícitamente predeterminada. Esto hace que el compilador genere las implementaciones predeterminadas para las funciones explícitamente predeterminadas, que son más eficientes que las implementaciones de funciones programadas manualmente.
Por ejemplo, cada vez que declaramos un constructor parametrizado, el compilador no creará un constructor predeterminado. En tal caso, podemos usar el especificador predeterminado para crear uno predeterminado. El siguiente código demuestra cómo:
CPP
// C++ code to demonstrate the // use of defaulted functions #include <iostream> using namespace std; class A { public: // A user-defined // parameterized constructor A(int x) { cout << "This is a parameterized constructor"; } // Using the default specifier to instruct // the compiler to create the default // implementation of the constructor. A() = default; }; int main() { // executes using defaulted constructor A a; // uses parameterized constructor A x(1); return 0; }
Salida :
This is a parameterized constructor
En el caso anterior, no tuvimos que especificar el cuerpo del constructor A() porque, al agregar el especificador ‘=default’, el compilador creará una implementación predeterminada de esta función.
¿Cuáles son las restricciones al hacer que las funciones sean predeterminadas?
Una función predeterminada debe ser una función miembro especial (constructor predeterminado, constructor de copia, destructor, etc.) o no tiene argumentos predeterminados. Por ejemplo, el siguiente código explica que las funciones de miembros no especiales no pueden ser predeterminadas:
CPP
// C++ code to demonstrate that // non-special member functions // can't be defaulted class B { public: // Error, func is not a special member function. int func() = default; // Error, constructor B(int, int) is not // a special member function. B(int, int) = default; // Error, constructor B(int=0) // has a default argument. B(int = 0) = default; }; // driver program int main() { return 0; }
¿Cuáles son las ventajas de ‘=default’ cuando simplemente podemos dejar un cuerpo vacío de la función usando ‘{}’?
Aunque los dos pueden comportarse de la misma manera, aún hay beneficios de usar el valor predeterminado en lugar de dejar un cuerpo vacío del constructor. Los siguientes puntos explican cómo:
- Dar un constructor definido por el usuario, aunque no hace nada, hace que el tipo no sea un agregado y tampoco sea trivial. Si desea que su clase sea un tipo agregado o trivial (o por transitividad, un tipo POD), entonces debe usar ‘= predeterminado’.
- El uso de ‘= predeterminado’ también se puede usar con constructores y destructores de copias. Un constructor de copia vacío, por ejemplo, no hará lo mismo que un constructor de copia predeterminado (que realizará una copia de sus miembros por miembro). El uso uniforme de la sintaxis ‘= default’ para cada una de estas funciones miembro especiales facilita la lectura del código.
Antes de C++ 11, el operador eliminar solo tenía un propósito: desasignar una memoria que se ha asignado dinámicamente.
El estándar C++ 11 introdujo otro uso de este operador, que es: Deshabilitar el uso de una función miembro. Esto se hace agregando =delete; especificador al final de la declaración de esa función.
Cualquier función miembro cuyo uso se haya deshabilitado mediante el especificador ‘=delete’ se conoce como una función eliminada explícitamente.
Aunque no se limita a ellos, pero esto se suele hacer a las funciones implícitas. Los siguientes ejemplos muestran algunas de las tareas en las que esta característica resulta útil:
Deshabilitar constructores de copias
CPP
// C++ program to disable the usage of // copy-constructor using delete operator #include <iostream> using namespace std; class A { public: A(int x): m(x) { } // Delete the copy constructor A(const A&) = delete; // Delete the copy assignment operator A& operator=(const A&) = delete; int m; }; int main() { A a1(1), a2(2), a3(3); // Error, the usage of the copy // assignment operator is disabled a1 = a2; // Error, the usage of the // copy constructor is disabled a3 = A(a2); return 0; }
Deshabilitar la conversión de argumentos no deseados
CPP
// C++ program to disable undesirable argument // type conversion using delete operator #include <iostream> using namespace std; class A { public: A(int) {} // Declare the conversion constructor as a // deleted function. Without this step, // even though A(double) isn't defined, // the A(int) would accept any double value // for it's argumentand convert it to an int A(double) = delete; }; int main() { A A1(1); // Error, conversion from // double to class A is disabled. A A2(100.1); return 0; }
Es muy importante tener en cuenta que una función eliminada está implícitamente en línea. Una definición eliminada de una función debe ser la primera declaración de la función. En otras palabras, la siguiente forma es la forma correcta de declarar una función como eliminada:
class C { public: C(C& a) = delete; };
Pero la siguiente forma de intentar declarar una función eliminada producirá un error:
CPP
// Sample C++ code to demonstrate the // incorrect syntax of declaring a member // function as deleted class C { public: C(); }; // Error, the deleted definition // of function C must be the first // declaration of the function. C::C() = delete;
¿Cuáles son las ventajas de borrar funciones explícitamente?
- La eliminación de funciones de miembros especiales proporciona una forma más limpia de evitar que el compilador genere funciones de miembros especiales que no queremos. (Como se demuestra en el ejemplo ‘Deshabilitar constructores de copias’).
- La eliminación de una función de miembro normal o funciones que no son miembros evita que las promociones de tipos problemáticos provoquen que se llame a una función no deseada (como se demuestra en el ejemplo «Deshabilitar la conversión de argumentos no deseados»).