书上的一个例子
#include <iostream.h>
class Complex
{
public:
Complex():real(0),imag(0){};
Complex(double r, double i):real(r),imag(i){};
Complex(double r):real(r),imag(0){}; // 定义转换构造函数
void Print(){
cout<<"real = " << real <<" image = "<<imag<<endl;
}
friend Complex operator+(Complex c,const Complex b)
{
return Complex(b.real + c.real, b.imag + c.imag);
}
private:
double real;
double imag;
};
int main()
{
Complex c;
c = 1.2; // 调用转换构造函数将1.2转换为Complex类型
c.Print();
Complex c1(2.9, 4.2);
double d = 3.1;
Complex c2 = c1 + 2.1; // 调用转换构造函数将3.1转换为Complex类型
c2.Print();
return 0;
}
1.
这是没问题的,下面我们先看看&引用赋值的问题
int a = 12;
int &b = a;//可以
int &c = 12;//无法 (int & ! const int)
第三句是不许的,或许我们认为&c = 12是把12这个类型值取别名可是
这个初始化错误提示明显告诉我们这是个赋值操作,而不是把int类型变量赋值int &
所以可以这样
const int &g = 12;
2.
从上面的错误我们可以猜想把int a = 12在vc编译器是这样的12是个const int常数类型的,经过=后它交给了int的类型
为了验证一下
const int a = 12;
int b = a;
编译通过
但是
const int a = 12;
int &b = a;
说明了一个引用的特点,不能将一个const T的类型交给T &类型
但是可以const T赋给 const T&
3。
我们回到上面的例子,且修改一下
friend Complex operator+(Complex &c,Complex &b)
{
return Complex(b.real + c.real, b.imag + c.imag);
}
这时会出现
如果了解了前面的1,2知识点,我们会发现我们把一个1.2 => const 变量类型交给了 &类型,上面我们讨论过是不予的,但是该程序中我们是想通过类型转换构造器来把const 类型的int 即1.2转换成Complex,然后再交给该程序中的友元重载函数的第二个参数,这样以来思路是没错的
但是这样
friend Complex operator+(Complex &c,const Complex &b)
{
//return Complex(b.real + c.real, b.imag + c.imag);
return NULL;
}
就可以编译通过了,
再看看一个矛盾的地方
#include <iostream.h>
class Complex
{
public:
Complex():real(0),imag(0){};
Complex(double r, double i):real(r),imag(i){};
Complex(double r):real(r),imag(0){}; // 定义转换构造函数
void Print(){
cout<<"real = " << real <<" image = "<<imag<<endl;
}
friend Complex operator+(Complex &c, Complex &b)
{
//return Complex(b.real + c.real, b.imag + c.imag);
return NULL;
}
private:
double real;
double imag;
};
int main()
{
double d = 3.1;
Complex c;
c = d; // 调用转换构造函数将1.2转换为Complex类型 ,隐式转换成功
c.Print();
Complex c1(2.9, 4.2);
//double d = 3.1;
Complex c2 = c1 + d; // 调用转换构造函数将3.1转换为Complex类型 ,但是看看下面的报错,上面都隐式转换成功了,这里却不行
c2.Print();
return 0;
}
4.那么我们猜想是不是因为 表达式中 + 1.2 是个数字常量导致的?
修改一下测试一下
#include <iostream.h>
class A
{
public:
double value;
A(double para)
{
value = para;
}
};
class Complex
{
public:
Complex():real(0),imag(0){};
Complex(double r, double i):real(r),imag(i){};
Complex(A r):real(r.value),imag(0){}; // 定义转换构造函数
void Print(){
cout<<"real = " << real <<" image = "<<imag<<endl;
}
friend Complex operator+(Complex &c, Complex &b)
{
//return Complex(b.real + c.real, b.imag + c.imag);
return NULL;
}
private:
double real;
double imag;
};
int main()
{
double d = 3.1;
Complex c;
//c = d; // 调用转换构造函数将1.2转换为Complex类型
c.Print();
Complex c1(2.9, 4.2);
//double d = 3.1;
A a(12);
Complex c2 = c1 + a; // 调用转换构造函数将3.1转换为Complex类型
c2.Print();
return 0;
}
结果还是报错
同样我们
friend Complex operator+(Complex &c, const Complex &b)
{
//return Complex(b.real + c.real, b.imag + c.imag);
return NULL;
}
就可以通过
5.原因猜想,在&类型被初始化时,vc并没有优先考虑隐式转换,而是直接进行判断类型是否匹配
基于4,我们再测试一次来验证我们的猜想
double d = 3.1;
A a(12);
Complex &c = a;
报错
而这样子
double d = 3.1;
A a(12);
Complex c = a; // 调用转换构造函数将1.2转换为Complex类型
Complex &c0 = c;
c0.Print();
这样 &c0 = c 的c变量是类型确定的,所以可以成功
Note:
不过我们在这里可看到其实C++的隐式转换是允许组合的例如
double d = 3.1;
A a(12);
Complex c = 11; // 调用A的转换构造函数将1.2转换为A类型,接着调用Complex的转换构造器将A类型转换为Complex
//*****************************************//
那么我们要怎么才能把Complex &c = a赋值成功呢?我们可以使用常量类型的引用
即const Complex &c = a 这样就能成功,把上面的改一下
double d = 3.1;
A a(12);
const Complex &c = a;
这样就没问题了,所以在隐式转换(C++使用构造器实现)时且要把最终装换的结果赋给&类型,&类型就必须为const类型的,才能让隐式转换成功
不过这里还有一个问题,就是用这种方法能不能解决隐式转换的组合情况呢?答案是不行的,看下一个
6.上面5的Note中我们实现了隐式转换的组合
//double d = 3.1;
//A a(12);
Complex c = 12;
等于
//double d = 3.1;
A a(12);
Complex c = a;
我们可以
double d = 3.1;
A a(12);
const Complex &c = a;
但是不可以
double d = 3.1;
A a(12);
const Complex &c = 12;
估计这是编译器的能力所限吧
6.
实践总结,如果通过
=> 表示转换
隐式转换A => B时,且B是个引用类型那么B必须是const类型的
--表示隐式组合
隐式转换A -- B =>C 即隐式转换两次时不能把声明为&,根据上面的规则,A转换为B时,B无法是个const B因为他是构造器构造出来的B