[C++] C++转换函数的使用

本文介绍C++中构造函数转换的概念及explicit关键字的作用,包括构造函数如何实现不同类型的自动转换,以及如何通过explicit避免不必要的类型转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.构造函数转换和explicit关键字

        在学习构造函数转换之前,先来复习下什么是自动类型转换:将一个标准类型的变量赋值给另一个标准类型的变量时,如果这两种类型兼容,则C++自动会将这个值转换为接收变量的值。

        什么是构造函数转换呢?通俗来讲,构造函数转换就是用户通过构造函数提供的定义类之间的自动类型转换。它的定义如下:
接收一个参数的构造函数可以实现这个参数类型和该类之间的自动转换。也就是说,只要是一个参数的构造函数,就可以作为转换函数,将类和其参数类型之间进行自动的转换。如:
MyClass(int i);//声明一个只有一个参数int的构造函数
Myclass mc;//通过默认参数获取mc对象
mc = 2;//这是可以的,通过构造函数转换完成了由int->MyClass的自动转换
        因此,可以将一个类定义成于基本类型或者另一个类相关,使得可以这这个相关类之间进行自动转换。然而,这样会导致意外的类型转换,怎么办呢?c++提供了一个关键字用于关闭这种特性:explicit关键字,该关键字用于关闭和用户通过构造转换函数定义的相关类之间的自动转换特性,但是可以显式的进行转换。下面通过示例来进一步理解这个特性。
Distance.h中,有类定义如下:
#pragma once
const double M2K = 1.6;
//定义一个类,表示距离,并分别用km和miles表示
class Distance
{
private :
	int  m_km;
	double m_miles;
public:
	Distance();//无参构造
	 Distance(int km);//只有一个int值的构造
	Distance(double mile);//只有一个double值的构造
	void show_by_km();//使用km输出
	void show_by_mile();//使用mile输出
	~Distance();//析构函数
};

Distance.cpp中实现类:

#include "distance.h"
#include <iostream>
Distance::Distance()
{
	m_km = m_miles = 0;
}
Distance::Distance(int km)
{
	m_km = km;
	m_miles = km * M2K;
}

Distance::Distance(double mile)
{
	m_miles = mile;
	m_km = (int)m_miles / M2K;
}

void Distance::show_by_km()
{
	std::cout << "distance:" << m_km <<" km" << std::endl;
}

void Distance::show_by_mile()
{
	std::cout << "distance:" << m_miles << " mile(s)" << std::endl;
}
Distance::~Distance()
{
}

main.cpp中:

#include <iostream>
#include "distance.h"
using namespace std;
int main()
{	//使用无参构造初始化Distance对象
	Distance d;
	d = 23.4;//自动类型转换,通过Distance(double)构造函数
	d.show_by_mile();
	d.show_by_km();
	return 1;
}

运行:


    如果在声明构造方法时加上explicit关键字,则会关闭自动转换,但可以进行强制转换:

	explicit Distance(int km);
	//explicit关闭Distance和double自动转换特性
	explicit Distance(double mile);

main.cpp中:

	Distance d;
	//由于使用了explicit关键字,只能进行强制转换
	d = (Distance)23.4;

    那么编译器在什么时候调用构造转换函数进行自动转换呢?以上例为例,他会在什么时候调用Distance(int)或者Distance(double)呢?如果使用了关键字explicit,那么只会在强制类型转换时调用;如果没有使用explicit关键字,则有四种情况下会使用构造转换函数:

    1.使用构造转换函数初始化时:Distance d(1.3);

    2.将double值赋值给Distance时:Distance d; d = 1.3;

    3.将double值传递给接收Distance对象或引用的函数时:

    4.函数的返回值为Distance类型,但返回double值时:

Distance getDistance(double s)
{
	return s;
}
    对于第四点需要注意,如果使用getDistance(double)传入参数为long类型,那么如果只存在Distance(double),那么他会先将long自动转换为double,然后将double自动转换为Distance;如果还存在Distance(int),那么编译器将无法确定是先将long转换为double呢还是int呢,因此存在二义性。

    2.转换函数

    到这里为止,掌握了通过构造转换函数(一个参数的构造函数)实现了参数类型转换为类,那么,类能否转换为参数类型呢?答案是可以的,但是不再是通过构造转换函数进行转换,构造转换函数只适用于从某种类型转换为类类型,要进行相反的转换,通过转换函数进行实现。

    2.1.转换函数的创建

    创建转换函数形式如下:

operator typeName();

    创建转换函数的规则:

    1.转换函数必须是类的成员函数;

    2.转换函数不能指定返回类型,但有返回值;

    3.转换函数没有参数;

    例如,如果要将Distance d转换为double类型,则可以在Distance中定义如下的转换函数:

operator double();

    下面还是以Distance为例,实现Distance转double:

示例2.转换函数的使用

    Distance.h中定义转换函数:

operator double();

    在Distance.cpp中编写转换函数:

Distance::operator double()
{
	return m_miles;
}

main.cpp中:

int main()
{	
	Distance distance;
	distance = 23.4;
	distance.show_by_mile();
	distance.show_by_km();
	//使用转换函数进行转换
	double temp = distance;
	cout << "temp:" <<temp<< endl;
	//这里没有重载<<操作符,为啥可以这样输出?
	cout << "distance:" << distance << endl;
	return 1;
}

        当调用double temp = d时编译器检测到类型不匹配,然后编译器会查看是否定义了与此匹配的转换函数,如果有定义,则进行转换,没有定义则编译失败。

        在上例中,并没有重载<<操作符,但是为什么在cout<<distance时可以输出呢?这里还是调用到了转换函数,在执行这句是,编译器发现不匹配,因此会首先寻找是否存在的匹配函数,结果发现了operator double(),因此将distance隐式地转换为double输出了。

        现在我再定义一个转换函数,用于将Distance转换为int,如下:

Distance.h中: 

	operator int();

Distance.cpp中:

Distance::operator int()
{
	//四舍五入
	return (int)(m_miles + 0.5);
}

然后继续运行,结果发现编译失败了:


        系统提示“有多个运算符<<”,原来是出现二义性了,因为当编译器查看是否有转换函数时,发现有两个相关类型的转换函数,不确定要转换为哪一个,因此出现二义性。

        要解决这个问题,可以进行显式的转换:

cout << "distance:" << (double)distance << endl; 

        和构造转换函数一样,转换函数也可以通过explicit关键字来取消其自动转换的特性,而是每次都通过显式的转换来进行转换,避免在用户不需要类型转换时就自动进行转换。

	explicit operator double();
	explicit operator int();

2.2.转换函数的优缺点

        利用转换函数可以自动执行隐式转换,但是也正是这个原因,当用户不需要转换时,也会自动进行转换。因此,应该谨慎使用隐式自动转换,因尽量通过关键字explicit取消自动转换,使用显式类型转换。


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值