1. Habrá ambigüedad en dos situaciones:
1.1 La clase A define un constructor de conversión que acepta objetos de clase B, y la clase B define un operador de conversión de tipos cuyo objetivo de conversión es la clase A.
struct B;
struct A
{
A() = default;
A(const B&); //把一个B转换为A
};
struct B{
operator A() const; //也是把B转换为A
}
A f(const A& a) {
return a;
}
B b;
A a = f(b); //二义性错误,含义是 f(B::operator A()) 还是f(A::A(const B&)) ???
Si realmente desea ejecutar la llamada anterior, la llamada que debe mostrarse:
A a1 = f(b.operator A());
A a2 = f(A(b));
1.2 La clase define múltiples reglas de conversión de tipos, y los tipos involucrados en estas conversiones pueden vincularse ellos mismos mediante otras conversiones de tipos.
Conversiones de varios tipos marcadas como tipos integrados
struct A{
//最好不要创建两个转换源都是算术类型的类型转换
A(int = 0);
A(double);
//最好不要创建两个转换对象都是算术类型的类型转换
operator int() const;
operator double() const;
};
void f2(long double);
A a;
f2(a); //二义性错误,含义是 f(A::operator int()),还是f(A::operator double())
long lg;
A a2(lg); //二义性错误,含义是A::A(int) 还是 A::A(double)
La conversión anterior provocará ambigüedad porque no existe la mejor coincidencia.
short s = 42;
A a3(s); //使用 A::A(int),因为short转换成int由于short转换成double
2. Principios de diseño
- No defina el mismo tipo de conversión para dos clases y no defina dos o más fuentes de conversión u objetivos de conversión en una clase que sean conversiones de tipos aritméticos.
- Si la clase contiene una o más conversiones de tipos, debe asegurarse de que solo haya un método de conversión entre el tipo de clase y el tipo de destino; de lo contrario, puede haber ambigüedad. Ej. El ejemplo más típico son los operadores aritméticos.
- Cuando usamos dos conversiones de tipo definido por el usuario, si hay una conversión de tipo estándar antes o después de la función de conversión, la conversión de tipo estándar determinará cuál es la mejor coincidencia
- Además de la conversión explícita al tipo bool, la definición de funciones de conversión de tipo debe evitarse y los constructores no explícitos "obviamente correctos" deben restringirse tanto como sea posible.
3. Funciones sobrecargadas y constructores de conversión
struct C
{
C(int);
};
struct D
{
D(int);
};
void manip(const C&);
void manip(const D&);
manip(10); //二义性错误,含义是manip(C(10))还是manip(D(10))
manip(C(10)); //正确,显示的指明调用
- Si necesita un constructor o una conversión de tipo forzada para cambiar el tipo de argumento al llamar a una función sobrecargada, esto generalmente significa que el diseño del programa es insuficiente.
4. Funciones sobrecargadas y conversión de tipos definidos por el usuario
Al llamar a funciones sobrecargadas, si hay más de un tipo de conversión y son diferentes entre sí, la llamada es ambigua. Incluso si una llamada requiere una conversión de tipo estándar adicional y la otra llamada puede coincidir exactamente, el compilador mostrará un error.
struct E
{
E(double){
}
};
manip(10); //二义性错误,含义是manip(C(10))还是manip(E(10))
[Cita]