2010-12-17 16 views
32

Entiendo que los constructores con un parámetro (no predeterminado) actúan como convertidores implícitos, que convierten de ese tipo de parámetro al tipo de clase. Sin embargo, explicit se puede utilizar para calificar cualquier constructor, aquellos sin parámetros (constructor predeterminado) o aquellos con 2 o más parámetros (no predeterminados).¿Por qué se permite explícitamente a los constructores y constructores predeterminados con 2 o más parámetros (no predeterminados)?

¿Por qué se permite explícitamente en estos constructores? ¿Hay algún ejemplo en el que esto sea útil para evitar algún tipo de conversión implícita?

+0

¿Por qué se puede prevenir? – Falmarri

+0

Falmarri: Si no se previene, ¿hay algún ejemplo en el que sea útil en un constructor predeterminado o en un constructor de parámetros> = 2? –

+0

Ver la respuesta de Adrian. ¿Por qué deberías prevenirlo? – Falmarri

Respuesta

7

Probablemente sea solo una conveniencia; no hay motivo para dis -perderlo, entonces, ¿por qué hacer la vida difícil a los generadores de códigos, etc.? Si marcó, las rutinas de generación de código tendrían que tener un paso adicional para verificar cuántos parámetros tiene el constructor generado.

De acuerdo con varioussources, no tiene ningún efecto cuando se aplica a constructores a los que no se puede llamar con exactamente un argumento.

+1

re "sin exactamente un parámetro", quiere decir, no tiene efecto cuando se aplica al constructor que no se puede invocar con exactamente un argumento. hay una diferencia ;-) –

+0

Distinción sutil, pero está bien :) Reparado. –

7

Quizás fue para mantener el mantenimiento. Al usar explicit en constructores de múltiples argumentos, uno puede evitar la introducción inadvertida de conversiones implícitas al agregar valores predeterminados a los argumentos. Aunque no lo creo; en cambio, creo que es solo que se permiten muchas cosas en C++ simplemente para no hacer que la definición del lenguaje sea más compleja de lo que ya es.

Quizás el caso más infame es devolver una referencia a la variable local no static. Necesitaría reglas complejas adicionales para descartar todas las cosas "sin sentido" sin afectar a ninguna otra cosa. Por lo tanto, solo está permitido, ceder UB si usa esa referencia.

O para los constructores, puede definir cualquier número de constructores predeterminados siempre que sus firmas sean diferentes, pero con más de uno es bastante difícil tener cualquiera de ellos invocado por defecto. :-)

Una mejor pregunta es, ¿por qué no se permite también explicit en los operadores de conversión?

Bueno, será, en C++ 0x. Entonces no había una buena razón por la que no. La razón real para no permitir explicit en operadores de conversión puede ser tan prosaica como la supervisión, o la lucha para obtener explicit adoptado en primer lugar, o simple priorización del tiempo del comité, o lo que sea.

Saludos & HTH.,

4

De acuerdo con la alta integridad C++ estándar de codificacióndebe declarar todos constructor de parámetro sinlge comoexplícitapara evitar un uso incidental en las conversiones de tipos. En el caso de que sea un constructor sin argumentos múltiples suponga que tiene un constructor que acepta múltiples parámetros que cada uno tiene un valor por defecto, convirtiendo el constructor en una especie de constructor por defecto y también un constructor de conversión:

class C { 
    public: 
    C(const C&); // ok copy 
    constructor C(); // ok default constructor 
    C(int, int); // ok more than one non-default argument 

    explicit C(int); // prefer 
    C(double); // avoid 
    C(float f, int i=0); // avoid, implicit conversion constructor 
    C(int i=0, float f=0.0); // avoid, default constructor, but 
           // also a conversion constructor 
}; 
void bar(C const &); 
void foo() 
{ 
    bar(10); // compile error must be 'bar(C(10))' 
    bar(0.0); // implicit conversion to C 
} 
35

Una razón sin duda es porque no duele

Una razón por la que se necesita es, si tiene argumentos predeterminados para el primer parámetro.El constructor se convierte en un constructor por defecto, pero todavía se puede utilizar como constructor de conversión de

struct A { 
    explicit A(int = 0); // added it to a default constructor 
}; 

C++ 0x hace uso real de la misma para los constructores de parámetros múltiples. En C++ 0x, se puede utilizar una lista de inicializadores para inicializar un objeto de clase. La filosofía es

  • si utiliza = { ... }, a continuación, se inicializa el objeto con una especie de "valor compuesto" que conceptualmente representa el valor abstracto del objeto, y que desea han convertido al tipo.

  • si utiliza un inicializador { ... }, llame directamente a los constructores del objeto, no necesariamente que desee especificar una conversión.

Considere este ejemplo

struct String { 
    // this is a non-converting constructor 
    explicit A(int initialLength, int capacity); 
}; 

struct Address { 
    // converting constructor 
    Address(string name, string street, string city); 
}; 

String s = { 10, 15 }; // error! 
String s1{10, 15}; // fine 

Address a = { "litb", "nerdsway", "frankfurt" }; // fine 

De esta manera, C++ 0x indica que la decisión de C++ 03, para permitir explícita sobre otros constructores, no era una mala idea en absoluto .

+0

Por lo tanto, 'explicit' en un constructor multiparamétrico da un resultado similar a' explicit' en un constructor de copia. –

+1

@James similar a explícito en cualquier constructor one-argument-callable :) Pero la diferencia de la inicialización de listas es que todavía considera un constructor explícito. Cuando se selecciona, se genera un diagnóstico. A diferencia de 'T t = v' que simplemente ignora los constructores explícitos, posiblemente prefiriendo un constructor no explícito, que el comité consideró como algo malo. –

+0

Oh. Sí. Tonto de mí. –

0

Estoy de acuerdo en que permitir cosas que no necesariamente tienen sentido es más simple que agregar toda la complejidad para atraparlas.

Solo por el bien de la discusión. No soy tan experto en detalles de C++, así que me pregunto si el comité de normalización de C++ alguna vez consideró una palabra clave implícita. Esto sería, naturalmente, opuesto a explícito y convertir la conversión de tipo implícita en no predeterminada.

class SomeClass 
{ 
public: 
    implicit SomeClass(int i); 
}; 

Sin la palabra clave, el siguiente no sería posible:

SomeClass foo = 6; 

Would C++ sea algo completamente diferente que va de esta manera en lugar de explícito?

Por supuesto, esto nos lleva a la pregunta de seguimiento si implícita debe ser anulado por ctors con más de un argumento ...

+0

Esta sería una buena idea, pero definitivamente rompería la compatibilidad con cualquier código, en cualquier lugar ... En este momento no es una opción. –

Cuestiones relacionadas