C++ 类型转换

本主题讨论C++如何处理用户自定义类型的转换。在讨论前,我们先复习一下C++如何处理内置类型转换的。

1.如果这两种类型兼容,则自动将值转换为接收变量的类型。例如

cpp 复制代码
long a = 'a'; //char 转为 long
double b = 11;//int 转为 double
int c = 3.33; //double 转为 int,有警告但可以转

2.类型不兼容,不能自动转换,但可以强制转换。例如

cpp 复制代码
int *p = 10;      //错误,类型错误
int *p = (int *)p;//可以.强制类型转换,这种赋值会出现野指针,但合法
1.转换构造函数

利用构造函数将基本类型或其它类构造当前类对象。

下面定义一个Complex复数类。

cpp 复制代码
//complex.h
#pragma once 
//复数类,演示类型转换
#include <iostream>
using namespace std;

class	Complex
{
private:
    int real;//实部
    int imag;//虚部
public:
    Complex() { real = imag = 0; }        //默认构造函数.内联函数
    Complex(int r) { real = r; imag = 0; }//带实部的构造函数,转换构造函数
    Complex(int r, int m) { real = r; imag = m; }//实部,虚部构造函数,内联函数
    Complex operator +(const Complex& com) const;//重载两个复数相加
    Complex operator -(const Complex & com)const;//重载两个复数相减
    friend ostream& operator<<(ostream& os, const Complex& com);//输出,友元函数
};
cpp 复制代码
//complex.cpp
#include "complex.h"

Complex Complex::operator +(const Complex& com) const//重载两个复数相加
{
    return Complex{ real + com.real, imag + com.imag };//最推荐
// return Complex(real + com.real, imag + com.imag); //推荐
 //return { real + com.real, imag + com.imag };//不太推荐
// return (real + com.real, imag + com.imag);//可能错误,禁止使用
}
Complex Complex::operator -(const Complex& com)const//重载两个复数相减
{
    return Complex(real-com.real,imag-com.imag);
}
ostream& operator<<(ostream& os, const Complex& com)//输出,友元函数
{
    os << com.real << "+" << com.imag << "i" << endl;
    return os;
}

测试代码如下:

cpp 复制代码
//test.cpp
#include "complex.h
int main()
{
    Complex c1 = {1,2};
    Complex c2 = {5,6};
    Complex c3 = 5;//自动类型转换,把int转为Complex类
    cout << c1 << c2<< c3<< endl;

    return 0;
}

其中c1,c2都是定义的正常的类型,但c3可以被一个整数赋值。

在C++中,接受一个参数的构造函数,可以将这种参数的类型转为该类类型,这种构造函数称为转换构造函数。如上把整型转为Complex类。

转换构造函数的作用是将一个其他类型转换成一个类类型。

cpp 复制代码
Complex(int r) { real = r; imag = 0; }//接受一个参数的构造函数

也就是说,可以编写这样的代码:

cpp 复制代码
Complex c3 = 5;//自动类型转换,把int转为Complex类
Complex c4 = Complex(5);//这个和上面的等价,把int转为Complex类

程序使用构造函数来创建一个类对象,这一过程称为隐式转换。

注意:只有接受一个参数的构造函数才能作为转换构造函数(如果有多个参数,但其它参数都有默认值也可以)。

cpp 复制代码
//下面的构造函数不能同时存在,会出现重定义(和上面的Complex(int r)也会重定义)
Complex(int r, int m=0) { real = r; imag = m; }//可以把int转为Complex类型
Complex(int r=0, int m=0) { real = r; imag = m; }//可以把int转为Complex类型

将构造函数用于自动类型转换似乎是不错的特性,但是,当你拥有更丰富的C++经验时,将发现这种自动转换有时并不是你想要的,而且会导致意外转换。

C++新增关键字explicit(明确的),用于关闭自动转换。也就是说,可以这样声明构造函数:

cpp 复制代码
explicit Complex(int r) { real = r; imag = 0; }//接受一个参数的构造函数,且不允许隐式转换

这样就不能自动转换,但可以显示转换,即:

cpp 复制代码
//Complex c3 = 5;//错误,不能自动(隐式)转换
Complex c3 = (Complex)5;//可以,显示转换
Complex c4 = Complex(5);//可以,显示转换

这样能更好的保证程序的可读性,同时不影响功能。

2.类型转换函数

上面的函数可以把数字转换为Complex类对象,那么可以做相反的转换吗?如下:

cpp 复制代码
Complex c4 = Complex(5);
int n = c4; //这样可以吗?

有办法可以这样做,但不是使用构造函数。构造函数只用于从某种类型到类类型的转换。要进行相反的转换,必须使用特殊的C++运算符函数--类型转换函数。
类型转换函数是把类类型转成其它类型的函数, 之后可以隐式或显示的进行相应的类型转换。

类型转换函数原型:

cpp 复制代码
operator 类型名()const;//这个类型名是需要转成的类型名,如int

●类型转换函数必须是类成员函数; //把类转为其它类型,当然是类成员函数

●类型转换函数不能指定返回类型; //返回的类型在类型名中已经指定

●类型转换函数不能有参数 . //类型转换,不需要其它参数

例如,把Complex转换为int类型的函数如下:

cpp 复制代码
operator int()const;//转换函数,把Complex转换为int,只返回实部。类成员函数

定义如下:

cpp 复制代码
Complex::operator int()const//转换函数,把Complex转换为int
{
    return real;//返回实部
}

测试如下:

cpp 复制代码
Complex c4 = Complex(5,1);
int n1 = c4;
int n2 = (int)c4;
int n3 = int(c4);
cout << c4;
cout << n1 << "," << n2 << "," << n3 << endl;

其中n1是隐式转换,n2,n3都是显式转换,总之通过类型转换函数可以把Complex转成int。

在C++11中可将类型转换函数声明为显示的explicit。如下:

cpp 复制代码
explicit operator int() const;//显式类型转换函数,把Complex转换为int,只返回实部

在调用时不能再进行隐式转换

cpp 复制代码
Complex c4 = Complex(5,1);
//int n1 = c4;    //错误,不能进行隐式转换
int n2 = (int)c4; //可以
int n3 = int(c4); //可以

警告:应谨慎地使用隐式类型转换函数。通常,最好选择是显式调用才会执行的函数。

总结,C++为类提供了下面的类型转换:

●只有一个参数的类构造函数用于将参数类型转换为类类型。如将int转换为Complex类型。

●类的成员函数--类型转换函数,用于将类类型转换为其它类型。如将Complex转换为int。

●上述两种转换最好都是显式转换,即在函数声明前加上explicit。

相关推荐
不写八个6 分钟前
Python办公自动化教程(005):Word添加段落
开发语言·python·word
HEX9CF11 分钟前
【CTF Web】Pikachu xss之href输出 Writeup(GET请求+反射型XSS+javascript:伪协议绕过)
开发语言·前端·javascript·安全·网络安全·ecmascript·xss
赵荏苒36 分钟前
Python小白之Pandas1
开发语言·python
丶Darling.38 分钟前
代码随想录 | Day26 | 二叉树:二叉搜索树中的插入操作&&删除二叉搜索树中的节点&&修剪二叉搜索树
开发语言·数据结构·c++·笔记·学习·算法
人生の三重奏1 小时前
前端——js补充
开发语言·前端·javascript
平凡的小码农1 小时前
JAVA实现大写金额转小写金额
java·开发语言
小飞猪Jay1 小时前
面试速通宝典——10
linux·服务器·c++·面试
yttandb1 小时前
重生到现代之从零开始的C语言生活》—— 内存的存储
c语言·开发语言·生活
我明天再来学Web渗透1 小时前
【hot100-java】【二叉树的层序遍历】
java·开发语言·数据库·sql·算法·排序算法
结衣结衣.2 小时前
python中的函数介绍
java·c语言·开发语言·前端·笔记·python·学习