C++之转换函数

1.转换函数

要点

  1. 转换函数必须是类方法
  2. 转换函数不能指定返回类型
  3. 转换函数不能有参数
  4. 转换函数不是构造函数

原型:operator typeName();
比如说转换为double类型的函数原型如下:
operator double();

1.1

/*1.转换函数,用于将类类型转换为某种类型(比如整型)
2.而构造函数可以将某种类型转换为类类型。这两个函数的作用是相反的。
3.转换函数是用户定义的强制转换类型,可以像使用强制转换类型那样使用它们
*/
#include<iostream>
using namespace std;

class Stonewt     
{
private:
	enum{Lbs_per_stn=14};  //一磅等于14石,磅和石都是一种重量单位
	int stone;  //石
	double pds_left;   //不够1石的部分
	double pounds;    // 磅  
public:
	Stonewt(double lbs);   //构造函数,这个构造函数只接受一个参数,可以作为转换函数,和通常的转换函数不一样,或者说叫转换构造函数更换好

};

Stonewt(double llbs)是构造函数,这个构造函数只接受一个参数,可以作为转换函数,和通常的转换函数不一样,这里实现的是从普通类型到类类型的转换。它在以下几个地方使用
1.初始化对象接受一个double参数的时候

Stonewt st(20.3);//这将创建一个对象,并将其成员初始化

2.一个double变量赋值给Stonewt对象的时候

Stonewt st;   //(1)
st=20.3;    //(2)

上面(1)将会创建一个对象,但是没有初始化。
(2)有点复杂,希望如果有错误的话,可以指出来。这也是个人猜想。
第(2)条语句的步骤:

  1. 首先类里面我还没有重载赋值运算符,那么c++会自动生成一个默认的赋值运算符,它的作用是将一个已经存在的对象的值(所有成员的值)直接复制(一模一样的复制)到新的对象里面。
  2. 那么st=20.3这句话很显然用默认赋值运算符无法处理(因为该类的默认赋值运算符函数只接受一个该类的对象)
  3. 那么当编译器运行到 Stonewt=20.3 这一步的时候,尝试将20.3传递给默认赋值运算符的形参
Stonewt& operator=(Stonewt st);   //默认赋值运算符,注意没有引用

那么会怎么样呢?将会这样:

Stonewt &operator=(Stonewt st(20.3));   //(3)

那么显然(3)的参数括号里面会调用构造函数,是不是有点套娃的感觉😋

  1. 最后发现,20.3已经被转换为类类型了,那么默认赋值运算符就可以用了,然后就进行成员的一一拷贝。
  2. 这就是第(2)句话的过程。应该没有什么问题吧。

3.返回值被声明为Stonewt的时候

Stonewt xxxx(xxx)
{
	...
	return x;     //如果x是double类型的,那么将会先先转换为一个临时的Stonewt变量,然后赋值给接受返回值的对象。
}

继续上面的类的定义
1.2

#include<iostream>
using namespace std;

class Stonewt     
{
private:
	enum{Lbs_per_stn=14};  //一磅等于14石,磅和石都是一种重量单位
	int stone;
	double pds_left;   
	double pounds;    
public:
	Stonewt(double lbs);   //构造函数,这个构造函数只接受一个参数,可以作为转换函数,和通常的转换函数不一样,或者说叫转换构造函数更换好
	Stonewt(int stn, double lbs);   //两个参数的构造函数就不能作为转换函数了
	Stonewt();   //默认构造函数
	~Stonewt();   //析构函数
	void show_lbs()const;   //输出英镑
	void show_stn()const;  //输出石
	operator int()const;    //转换函数,将Stonewt类转换为int类型
	operator double()const;   //转换函数,将Stonewt类转换为double类型
};

说明一下转换函数:

  1. 虽然两个转换函数没有声明返回类型,但是这两个函数也将返回所需的值。
  2. 这里定义的int转换函数不是传统的去掉小数部分,而是根据四舍五入来转换。(自己可以定义)

1.3,cpp

/*
1.转换函数,用于将类类型转换为某种类型(比如整型)
2.而构造函数可以将某种类型转换为类类型。这两个函数的作用使相反的。
3.转换函数是用户定义的强制转换类型,可以像使用强制转换类型那样使用它们
*/

#include<iostream>
using namespace std;

class Stonewt     
{
private:
	enum{Lbs_per_stn=14};  //1石等于14磅,磅和石都是一种重量单位
	int stone;
	double pds_left;   
	double pounds;    
public:
	Stonewt(double lbs) { pounds = lbs; }   //构造函数,这个构造函数只接受一个参数,可以作为转换函数,和通常的转换函数不一样,这里实现的
	//是从普通类型到类类型的转换。它在以下几个地方使用
	//1.初始化对象接受一个double参数的时候   2.一个double变量赋值给Stonewt对象的时候
	//详细讲一下第二点:
	Stonewt(int stn, double lbs);   //两个参数的构造函数就不能作为转换函数了
	Stonewt();
	~Stonewt();
	void show_lbs()const;   //输出英镑
	void show_stn()const;  //输出石
	operator int()const;    //转换函数,将Stonewt类转换为int类型
	operator double()const;   //转换函数,将Stonewt类转换为double类型
};

Stonewt::Stonewt(double lbs)
{
	stone = int(lbs) / Lbs_per_stn;   //1石等于磅的数量除14
	pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);   //不够1石的磅
	pounds = lbs;   //磅
}

Stonewt::Stonewt(int stn, double lbs)
{
	stone = stn;  //石
	pds_left = lbs;   
	pounds = stn * Lbs_per_stn + lbs;   //磅
}

Stonewt::Stonewt()
{
	stone = pounds = pds_left = 0;
}

Stonewt::~Stonewt()  //啥也没有
{
}

void Stonewt::show_stn()const
{
	cout << stone << " stone, " << pds_left << " pounds\n";
}

void Stonewt::show_lbs()const
{
	cout << pounds << " pounds\n";
}

Stonewt::operator int()const
{
	return int(pounds + 0.5);
}

Stonewt::operator double()const
{
	return pounds;
}

1.3的说明
很显然上面的转换函数没有返回类型,但是函数体里面却使用了return
1.4

Stonewt::operator int()const
{
	return int(pounds + 0.5);
}

Stonewt::operator double()const
{
	return pounds;
}
int main()
{
	Stonewt poppins(9, 2.8);
	double p_wt = poppins;
	cout << "Convert to double=> ";
	cout << "Poppins: " << p_wt << "pounds.\n";
	cout << "Convert to int=> ";
	cout << "Poppins: " << int(poppins) << " pounds.\n";
	return 0;
}

注意,最后一个cout

cout << "Poppins: " << int(poppins) << " pounds.\n";

如果不适用强制类型转换,会怎么样?、
编译器会指出二义性错误,因为该类里面有两个转换函数,编译器不知道用哪一个。
那么如果只有一个转换函数,编译器就不会报错,但是不管有几个转换函数,最好还是使用强制转换!

举个例子:

long gone=poppins;   //这会产生二义性

为什么呢会产生二义性呢?因为不论是将poppins转换为int,还是转换为double,都可以赋值给long类型。
那么就需要使用强制类型转换。

long gone=(double)poppins;
long gone=double(poppins);

上面两种方法是一样的。

2.转换函数的缺点

和转换构造函数(仅仅接受一个参数的构造函数)一样,转换函数提供执行自动,隐式转换的函数所存在的问题是:在用户不希望进行转换的时候,它却转换了。
想必都知道了,,,
explicit !!!

class Stonewt
{	
.....
	explicit operator int()const;
	explicit operator double()const;
}

那么有了这个声明之后,就只能使用强制转换来调用这些函数了,就不能隐式转换了!

3.转换函数和友元函数

假设没有定义operator double()函数。我们来重载加法运算符

/*
1.转换函数,用于将类类型转换为某种类型(比如整型)
2.而构造函数可以将某种类型转换为类类型。这两个函数的作用使相反的。
3.转换函数是用户定义的强制转换类型,可以像使用强制转换类型那样使用它们
*/

#include<iostream>
using namespace std;

class Stonewt     
{
private:
	enum{Lbs_per_stn=14};  //1石等于14磅,磅和石都是一种重量单位
	int stone;
	double pds_left;  
	double pounds;    
public:
	Stonewt(double lbs);  //构造函数,这个构造函数只接受一个参数,可以作为转换函数,和通常的转换函数不一样,这里实现的
	//是从普通类型到类类型的转换。它在以下几个地方使用
	//1.初始化对象接受一个double参数的时候   2.一个double变量赋值给Stonewt对象的时候
	//详细讲一下第二点:
	Stonewt(int stn, double lbs);   //两个参数的构造函数就不能作为转换函数了
	Stonewt();
	~Stonewt();
	void show_lbs()const;   //输出英镑
	void show_stn()const;  //输出石
	operator int()const;    //转换函数,将Stonewt类转换为int类型
	operator double()const;   //转换函数,将Stonewt类转换为double类型
	//Stonewt operator+(const Stonewt& st)const ;
	friend Stonewt operator+(const Stonewt& st1, const Stonewt& s2);  //友元
	friend ostream & operator<<(ostream &os, const Stonewt & st)
	{
		os << st.pds_left << " " << st.pounds << endl;
		return os;
	}
};

Stonewt::Stonewt(double lbs)
{
	stone = int(lbs) / Lbs_per_stn;   //1石等于磅的数量除14
	pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);   //不够1石的磅
	pounds = lbs;   //磅
}

Stonewt::Stonewt(int stn, double lbs)
{
	stone = stn;  //石
	pds_left = lbs;   
	pounds = stn * Lbs_per_stn + lbs;   //磅
}

Stonewt::Stonewt()
{
	stone = pounds = pds_left = 0;
}

Stonewt::~Stonewt()  //啥也没有
{
}

void Stonewt::show_stn()const
{
	cout << stone << " stone, " << pds_left << " pounds\n";
}

void Stonewt::show_lbs()const
{
	cout << pounds << " pounds\n";
}

Stonewt::operator int()const
{
	return int(pounds + 0.5);
}

//Stonewt::operator double()const
//{
//	return pounds;
//}
//Stonewt Stonewt::operator+(const Stonewt& st)const  //重载加法作为类成员函数
//{
//	double pds = pounds + st.pounds;
//	Stonewt sum(pds);
//	return sum;
//}

Stonewt operator+(const Stonewt& st1, const Stonewt& st2)
{
	double pds = st1.pounds + st2.pounds;
	Stonewt sum(pds);
	return sum;
}
int main()
{

	Stonewt jennySt(9, 12);
	double kenny=129.2;
	Stonew total;
	total=jennySt+kenny;  //先调用加法函数,发现kenny是double类型
	//然后又发现有Stonewt(double),那么就可以隐式转换为类类型,然后调用函数。
	cout << total;
	return 0;
}

注意
如果上面定义了operator double(),那么下面这句话会怎么样:

total=jennySt+kenny; //两种可能
//第一种:kenny通过转换构造函数变成Stonewt类,然后调用重载加法运算符函数
//第二章,jennyst通过operator double()转换为double类型,然后实现两个
//double类型的普通相加

这就意味着会产生二义性。

所以,总结:

要将double类和Stonewt类相加,有两个方法

  1. 将加法运算符函数声明为友元
  2. 将加法运算符重载为一个显示使用double类型参数的函数
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值