C++ day19 使用类(四)类的类型转换,转换函数

隐式自动类型转换(兼容的类型才会自动转换,有风险,需谨慎)

都表示数字的类型就是兼容的,因为第一,都表示数字,第二,既然都是数字,所以可以执行的方法是一样的。比如加减乘除。因此C++才允许自动转换,当然这其中仍然有风险,比如缩窄变换,把double给int,就会损失精度。

你像指针和int,就不是兼容的类型,虽然地址说白了也是整数,但是可以执行的操作不一样啊,你不能把指针拿来乘除啊,况且指针的加减法和数字的加减也是不一样的。所以指针和int是不会自动转换类型的。

只有一个参数的构造函数可以作为自动类型转换函数(从任意类型到类类型,不可反转)

只有一个参数的构造函数或者有多个参数但是除了第一个参数以外的参数都有默认值的构造函数。可以作为自动类型转换函数。

示例

//stonewt.h
#ifndef STONEWT_H_
#define STONEWT_H_

class Stonewt{
private:
	int stones;//英石为单位计量重量
	double pounds;//磅为单位计量
	double pounds_left;//用英石计量后剩余的磅数
	enum {PDS_PER_STONE = 14};//或static const int PDS_PER_STONE = 14;
	void set_stones_lpds(double pds);
public:
	Stonewt();
	Stonewt(double pds);
	Stonewt(int sts, double pds = 0.0);
	~Stonewt();
	void showPounds() const;
	void showStones() const;
	void show() const;
};
#endif
//stonewt.cpp
#include <iostream>
#include "stonewt.h"

void Stonewt::set_stones_lpds(double pds)
{
	stones = int (pds) / PDS_PER_STONE;
	//如果不先转为int则无法使用运算符%,因为%的操作数只能是整数
	pounds_left = int (pds) % PDS_PER_STONE + (pds - int (pds));
}



Stonewt::Stonewt()
{
	pounds = stones = pounds_left = 0;
}

Stonewt::Stonewt(double pds)
{
	pounds = pds;
	this->set_stones_lpds(pds);
}

Stonewt::Stonewt(int sts, double pds)
{
	this->set_stones_lpds(pds);
	stones += sts;
	pounds = stones * PDS_PER_STONE + pounds_left;
}

Stonewt::~Stonewt()
{

}

void Stonewt::showPounds() const
{
	std::cout << "Pounds: " << pounds << '\n';
}

void Stonewt::showStones() const
{
	std::cout << "Stones: " << stones << ", pounds left: " << pounds_left << '\n';
}

void Stonewt::show() const
{
    showStones();//可以省略this指针,相当于this->showStones();
    this->showPounds();
    std::cout << '\n';
}
//main.cpp
#include <iostream>
#include "stonewt.h"

int main()
{
	Stonewt w1 = 39.0;//隐式自动类型转换,使用原型Stonewt(double pds);
	Stonewt w2 = 39;//隐式自动类型转换,使用原型Stonewt(int sts, double pds = 0.0);
    Stonewt w3(39);//显式强制类型转换,使用原型Stonewt(int sts, double pds = 0.0);
    Stonewt w4;

    w1.show();
    w2.show();
    w3.show();
    w4.show();
    
	return 0;
}

输出

Stones: 2, pounds left: 11
Pounds: 39

Stones: 39, pounds left: 0
Pounds: 546

Stones: 39, pounds left: 0
Pounds: 546

Stones: 0, pounds left: 0
Pounds: 0

可以从这里例子充分看到,只有一个参数的构造函数,或者有多个参数但是除了第一参数以外都是默认参数的构造函数确实进行了自动类型转换。把int转换为Stonewt,或者把double转换为Stonewt类型

出错:

  • 忘记在const成员函数的定义中写const
  • 显示函数的原型竟然忘记写返回类型void。。。。。???
  • 对%运算符用了double类型的操作数,直到编译器报错都半天没反应过来。。。。

非常错误的代码:

void Stonewt::set_stones_lpds(double pds)
{
	stones = pds / PDS_PER_STONE;
	pounds_left = pds % PDS_PER_STONE;
}

在这里插入图片描述

  • 我以为Stonewt w2 = 39;会使用Stonewt(double pds);原型,先把39从int转换为double,再使用。其实不然,编译器一找就找到了第一个参数就是int且剩余参数是默认参数的版本,为何还要费更多事情,编译器认为Stonewt(int sts, double pds = 0.0);才是最符合的版本。

关键字explicit禁止隐式自动类型转换(只需要在原型写)

就像friend关键字一样,只需要写在原型上

Stonewt w1 = 39.0;//报错,原型:explicit Stonewt(double pds);
Stonewt w2 = 39;//报错,原型:explicit Stonewt(int sts, double pds = 0.0);

所以
在这里插入图片描述

转换函数(特殊的C++运算符函数,强制类型转换运算符,没有返回类型,也没有参数)

在这里插入图片描述

但是虽然没有返回类型,也要返回值,返回的类型就是typeName类型的

示例 四舍五入:return int (pounds + .5);

//main.cpp
#include <iostream>
#include "stonewt.h"

int main()
{
	Stonewt w1 = 39.0;//原型: Stonewt(double pds);
	Stonewt w2 = 39;//原型: Stonewt(int sts, double pds = 0.0);
    Stonewt w3(39);//Stonewt(int sts, double pds = 0.0);
    Stonewt w4;

    w1.show();
    w2.show();
    w3.show();
    w4.show();

	double pds = w1;
	int pds_int = w2;
    std::cout << pds << ' ' << pds_int << '\n';
	return 0;
}

头文件的类声明中多了两个原型:

operator int() const;
operator double() const;

方法文件多了两个定义:

//虽然没有返回类型,却有返回值
Stonewt::operator int() const
{
	return int (pounds + .5);//四舍五入
}

Stonewt::operator double() const
{
	return pounds;
}
Stones: 2, pounds left: 11
Pounds: 39

Stones: 39, pounds left: 0
Pounds: 546

Stones: 39, pounds left: 0
Pounds: 546

Stones: 0, pounds left: 0
Pounds: 0

39 546

把explicit用于转换函数

示例1 用explicit:隐式不可以,显式可以
explicit operator int() const;
explicit operator double() const;
//main.cpp
#include <iostream>
#include "stonewt.h"

int main()
{
    Stonewt Temp(25, 20);
    //显式强制类型转换
    long gone = double (Temp);//或C语法(double) Temp;
    long go = int (Temp);//或C语法:(int) Temp;
    std::cout << gone << '\n';
    std::cout << go << '\n';

	return 0;
}

程序使用了强制转换,把Stonewt类型转换为double和int,然后又隐式准换为long

370
370
示例2 不用explicit:隐式显式都可以
//main.cpp
#include <iostream>
#include "stonewt.h"

int main()
{
    Stonewt Temp(25, 20);
    //隐式自动类型转换
    int INT = Temp;//operator int() const;
    double DOUBLE = Temp;//operator double() const;
    std::cout << INT << '\n';
    std::cout << DOUBLE << '\n';

    //显式强制类型转换
    long gone = double (Temp);//或C语法(double) Temp;
    long go = int (Temp);//或C语法:(int) Temp;
    std::cout << gone << '\n';
    std::cout << go << '\n';

	return 0;
}
370
370
370
370
示例3 不用explicit也有办法禁止隐式转换(不再使用转换函数,而用成员函数实现转换)
//main.cpp
#include <iostream>
#include "stonewt.h"

int main()
{
    Stonewt Temp(25, 20);
    //隐式自动类型转换

    int INT;
    INT = Temp.Stonewt_to_int();
    //INT = Temp;//报错,不再允许隐式转换
    double DOUBLE;
    DOUBLE = Temp.Stonewt_to_double();
    //DOUBLE = Temp;//报错,不再允许隐式转换
    std::cout << INT << '\n';
    std::cout << DOUBLE << '\n';

	return 0;
}

原型:

int Stonewt_to_int() const;
double Stonewt_to_double() const;

定义:

int Stonewt::Stonewt_to_int() const
{
    return int (pounds + .5);
}

double Stonewt::Stonewt_to_double() const
{
    return pounds;
}
370
370

潜在风险:不希望转换的时候也转换(这一点上,显式强制转换 胜


比如你哪天精神不济,写了如下代码:

//main.cpp
#include <iostream>
#include "stonewt.h"

int main()
{
    Stonewt Temp(25, 20);
    Temp.show();
    int temp = 1;
    int ar[10] = {};

    std::cout << ar[Temp] << '\n';

	return 0;
}

转换函数不用explicit:

operator int() const;
operator double() const;

于是,函数无错误无警告的通过了,得到了错误结果,但是如果用了explicit,编译器就会报错,这一点上,显式强制转换胜

Stones: 26, pounds left: 6
Pounds: 370

529538960

显式强制类型转换(无法自动转换才强制转换)

相关知识已经嵌在上面的隐式自动类型转换中了

总结

类的类型转换中

  • 如果想把类型a转化为类类型,则可以通过构造函数实现:只有一个a类型参数,或者有多个参数但是除第一个a类型参数外都是默认参数。
  • 如果想把类类型转换为其他类型,则要创建被称为转换函数的成员函数。他没有返回类型,但是要返回被转换为的目标类型的值。
  • 可以用explicit防止转换函数被用于隐式转换。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值