一、自动类型转换
1.引言
对于内置类型,如果两种数据类型是兼容的,C++可以自动转换,如果从更大的数转换为更小的数,可能会被截断或损失精度。
C++不自动转换不兼容的类型,下面语法是非法的:
int* ptr = 8;
不能自动转换时,可以使用强制类型转换:
int* p = (int*) 8;
2.在类中的应用
如果某种类型与类相关,从某种类型转换为类的类型是有意义的: string str = "我是小马哥“。可以理解为把字符数组转换成了string对象。
在C++中,一个参数的构造函数为将类型与该参数相同的值转换为类提供了蓝图。这一过程称为隐式转换,它是自动进行的,不需要显示强制类型转换。
#include <iostream>
using namespace std;
class supman
{
public:
string m_name;
int m_age;
double m_score;
supman()
{
m_name.clear(); m_age = 0; m_score = 0;
cout << "调用supman()默认构造函数" << endl;
}
void show()
{
cout << "姓名:" << m_name << " 年龄:" << m_age << " 分数:" << m_score << endl;
}
supman(int age)
{
m_age = age; m_name.clear();m_score = 0;
cout << "调用supman(int age)构造函数" << endl;
}
};
int main()
{
supman boy(18); //① 常规写法
//supman boy = supman(16); //② 显示转换
//supman boy = 14; //③ 隐式写法
//supman boy; //④ 创建对象,
//boy = 20; // 用supman(20)创建临时对象,再赋值给boy
boy.show();
}
运行结果①为:
调用supman(int age)构造函数
姓名: 年龄:18 分数:0
C:\code\day\x64\Debug\day.exe (进程 31184)已退出,代码为 0。
按任意键关闭此窗口. . .
运行结果②为:
调用supman(int age)构造函数
姓名: 年龄:16 分数:0
C:\code\day\x64\Debug\day.exe (进程 4268)已退出,代码为 0。
按任意键关闭此窗口. . .
运行结果③为:
调用supman(int age)构造函数
姓名: 年龄:14 分数:0
C:\code\day\x64\Debug\day.exe (进程 25012)已退出,代码为 0。
按任意键关闭此窗口. . .
运行结果④为:
调用supman()默认构造函数
调用supman(int age)构造函数
姓名: 年龄:20 分数:0
C:\code\day\x64\Debug\day.exe (进程 41140)已退出,代码为 0。
按任意键关闭此窗口. . .
3.注意细节
1)一个类可以有多个转换函数。//前提是数据类型不同,编译器可以区分,否则出现二义性。
2)多个参数的构造函数,除了第一个参数外,如果其它参数都有缺省值,也可以作为转换函数。
3)supman(int)的隐式转换的场景:
- 将supman对象初始化为int值时;//supman boy = 18;
- 将int值赋值给supman对象时; //supman boy; boy=18;
- 将int值传递给接受supman参数的函数时;
#include <iostream> using namespace std; class supman { public: string m_name; int m_age; double m_score; supman() { m_name.clear(); m_age = 0; m_score = 0; cout << "调用supman()默认构造函数" << endl; } void show() { cout << "姓名:" << m_name << " 年龄:" << m_age << " 分数:" << m_score << endl; } supman(int age) { m_age = age; m_name.clear();m_score = 0; cout << "调用supman(int age)构造函数" << endl; } }; void funct(supman man) { man.show(); } int main() { funct(18); }
运行结果如下:
调用supman(int age)构造函数 姓名: 年龄:18 分数:0 C:\code\day\x64\Debug\day.exe (进程 29212)已退出,>代码为 0。 按任意键关闭此窗口. . .
- 返回值被声明为supman的函数试图返回int值时;
部分代码:
supman funct() { return 18; } int main() { funct(); }
运行结果如下:
调用supman(int age)构造函数 C:\code\day\x64\Debug\day.exe (进程 16616)已退出,>代码为 0。 按任意键关闭此窗口. . .
- 在上述任意一种情况下,使用可转换为int类型的内置类型时;
部分代码如下:
supman funct() { char c = 11; return c; } int main() { funct(); }
运行结果如下:
调用supman(int age)构造函数 C:\code\day\x64\Debug\day.exe (进程 35744)已退出,代码为 0。 按任意键关闭此窗口. . .
4)如果自动类型转换有二义性,编译将报错。
将构造函数用作自动类型转换函数似乎是一项不错的特性,但有时候会导致意外的类型转换。explicit关键字用于关闭这种自动特性,但任允许显示转换,不允许隐式转换。
explicit supman (int age);
supman g=8; //错误
supman g=supman(8); //显示转换,可以
supman g=(supman)8; //显示转换,可以
在实际开发中,如果强调的是构造,建议使用explicit;如果强调的是类型转换,则不使用explicit。
二、转换函数
构造函数只能用于从某种类型到类的类型转换,如果要进行相反的转换,可以使用特殊的运算符函数-转换函数。
1.语法
operator 数据类型();
注意:转换函数必须是类的成员函数;不能指定返回值类型;不能有参数。
可以让编译器决定选择转换函数(隐式转换),可以像使用强制类型转换那样使用它们(显示转换)。
#include <iostream>
using namespace std;
class supman
{
public:
string m_name;
int m_age;
double m_score;
supman():m_name("小马哥"),m_age(18),m_score(88.88)
{
cout << "调用supman()默认构造函数" << endl;
}
operator string() { return m_name; }
operator int() { return m_age; }
operator double() { return m_score; }
};
int main()
{
supman boy;
//以下三行为隐式转换
string a = boy; cout << "a=" << a << endl;
int b = boy; cout << "b=" << b << endl;
double c = boy; cout << "c=" << c << endl;
//以下为显示转换
//int n = (int) boy;
}
运行结果如下:
调用supman()默认构造函数
a=小马哥
b=18
c=88.88
C:\code\day\x64\Debug\day.exe (进程 37900)已退出,代码为 0。
按任意键关闭此窗口. . .
2.注意事项
如果隐式转换存在二义性,编译器将报错。
在C++98中,关键字explicit不能用于转换函数,但C++11消除了这种限制,因此,在C++11中,可以将转换运算符声明为显示的。
还有一种方法:用一个功能相同的非转换函数替换转换函数,只要当函数被显示的调用时才会执行。
#include <iostream>
using namespace std;
class supman
{
public:
string m_name;
int m_age;
double m_score;
supman():m_name("小马哥"),m_age(18),m_score(88.88)
{
cout << "调用supman()默认构造函数" << endl;
}
operator string() { return m_name; }
//operator int() { return m_age; }
operator double() { return m_score; }
int to_int() //普通函数
{ return m_age; }
};
int main()
{
supman boy;
string a = boy; cout << "a=" << a << endl;
//int b = boy; cout << "b=" << b << endl;
int b = boy.to_int(); cout << "b=" << b << endl;
double c = boy; cout << "c=" << c << endl;
}
运行结果如下:
调用supman()默认构造函数
a=小马哥
b=18
c=88.88
C:\code\day\x64\Debug\day.exe (进程 44528)已退出,代码为 0。
按任意键关闭此窗口. . .