c++ - resueltos - ¿Cuál es el punto de eliminar el constructor de clase predeterminado?
que es una clase en programacion (4)
Me estoy preparando para mi examen de CPP y una de las preguntas es: ¿puede eliminar el constructor de clases predeterminado y, de ser así, cuál sería la razón para hacerlo? OK, entonces obviamente puedes hacerlo:
class MyClass
{
public:
MyClass() = delete;
};
pero no entiendo por qué lo harías?
A veces las clases no están destinadas a ser instanciadas.
Un ejemplo que no se ha mencionado hasta ahora son las clases de "rasgo". Por ejemplo, considere std::char_traits
, aunque el estándar no ha dicho que su constructor predeterminado deba eliminarse, su constructor predeterminado es de poca utilidad porque la clase en sí está vacía, todas sus funciones son estáticas y no es necesario para ser instanciado para usar los alias de tipo que proporciona.
Las clases de rasgos por lo general solo se usan para admitir otras clases (por lo general, otras clases de plantilla), por lo tanto, a menudo puede tener sentido eliminar su constructor predeterminado, para reforzar la idea de que solo son un tipo de ayudante y que en realidad no se deben usar como un objeto.
Considere la siguiente clase:
struct Foo {
int i;
};
Esta clase es un agregado, y puede crear una instancia con las tres definiciones siguientes:
int main() {
Foo f1; // i uninitialized
Foo f2{}; // i initialized to zero
Foo f3{42}; // i initialized to 42
}
Ahora, digamos que no le gustan los valores no inicializados y el comportamiento indefinido que podrían producir. Puedes eliminar el constructor por defecto de Foo
:
struct Foo {
Foo() = delete;
int i;
};
Foo
sigue siendo un agregado, pero solo las dos últimas definiciones son válidas, la primera es ahora un error de compilación.
Hay algunas razones para eliminar el constructor predeterminado.
- La clase es puramente estática y no desea que los usuarios realicen una instancia de una clase solo con métodos / miembros estáticos. Un ejemplo de tal clase podría ser uno que implemente el patrón de diseño de fábrica usando solo métodos estáticos para crear nuevas clases.
- No tendría sentido que la clase tuviera un constructor predeterminado (ya que requiere parámetros / No hay valores predeterminados que tengan sentido para la clase). En este caso,
= delete
es una cuestión de estilo, como dijo @HolyBlackCat, pero aclara su intención al indicar al código del cliente que solo llame al constructor con los parámetros. - No desea datos no inicializados para una clase agregada.
Si la segunda declaración no estaba clara, considere el siguiente ejemplo:
class A
{
public:
//A() = delete;
A(int, int) {};
};
Si intentara llamar al constructor predeterminado en este momento, obtendría un error que se vería como (GCC 7.2):
error: no hay función coincidente para la llamada a ''A :: A ()''
Sin embargo, si no comenta la línea con = delete
, obtendrá lo siguiente:
error: uso de la función eliminada ''A :: A ()''
Esto deja en claro de manera explícita que uno está tratando de usar un constructor eliminado en comparación con el otro error, lo cual no está claro.
Múltiples opciones por defecto
Eliminar el constructor predeterminado de una clase es una buena idea cuando existen varias opciones para el estado predeterminado o no inicializado. Por ejemplo, supongamos que tengo una clase,
template<typename F>
class Polynomial;
que representa un polinomio sobre un campo, F
En este caso, hay muchas opciones para un valor predeterminado del polinomio. Una podría ser la identidad de los polinomios en adición, es decir, cero, pero también podríamos tener la identidad multiplicativa, la unidad. Depende de cómo pretenda el usuario razonar acerca de la clase y cómo se utiliza.
Sin elección por defecto
El otro caso notable es cuando, en lugar de tener múltiples estados predeterminados que puedan tener sentido, no tenemos ninguno. Por ejemplo, supongamos que tenemos una clase que representa una variedad o superficie.
¿Qué es entonces el Manifold()
? Es un espacio vacío, sin nada, sin superficie, sin noción de distancia o métrica. Pero entonces no tiene sentido pensar en ello como algo múltiple, sino tal vez algo más general como un espacio topológico.
Por lo tanto, en este caso, también optaría por eliminar el constructor predeterminado.