1 再论类型转换
-
标准数据类型之间会进行隐式的类型安全转换
-
转换规则
char -> ↓ int -> unsigned int -> long -> unsigned long -> float -> double short ->
-
示例1:基本数据类型之间的隐式类型转换
-
Demo
#include <iostream> #include <string> using namespace std; int main() { short s = 'a'; // 隐式类型转换:char->short unsigned int ui = 1000; // 隐式类型转换:int->unsigned int int i = -2000; double d = i; // 隐式类型转换:int->double cout << "d = " << d << endl; // -2000 cout << "ui = " << ui << endl; // 1000 cout << "ui + i = " << ui + i << endl; // 4294966296 = unsigned int + (unsigned int)(int) => 1000 + (unsgined int)(-2000) => 1000 + // unsigned int + int => unsigned int + (unsigned int)int => unsigned int > 0 if( (ui + i) > 0 ) { cout << "Positive" << endl; } else { cout << "Negative" << endl; } // short + char => (int)short + (int)char => int cout << "sizeof(s + 'b') = " << sizeof(s + 'b') << endl; // 4 return 0; }
-
编译运行
-2000 1000 Positive 4
-
-
【问题】普通类型与类类型之间能否进行类型转换?类类型之间能否进行类型转换?
- 普通类型 => 类类型:转换构造函数
- 类类型 => 普通类型:类型转换函数
- 类类型 => 类类型:类型转换函数/转换构造函数
2 普通类型 ---> 类类型?
-
示例2:普通类型 => 类类型
-
Demo1:直接尝试 int => Test
#include <iostream> using namespace std; class Test { }; int main() { Test t; t = 5; // int => Test return 0; }
-
编译
test.cpp: In function ‘int main()’: test.cpp:13:7: error: no match for ‘operator=’ (operand types are ‘Test’ and ‘int’) t = 5; ^ test.cpp:5:7: note: candidate: Test& Test::operator=(const Test&) class Test ^ test.cpp:5:7: note: no known conversion for argument 1 from ‘int’ to ‘const Test&’
-
Demo2:利用强制类型转换
#include <iostream> using namespace std; class Test { }; int main() { Test t; t = (Test)5; // int => Test return 0; }
-
编译
test.cpp: In function ‘int main()’: test.cpp:14:15: error: no matching function for call to ‘Test::Test(int)’ t = (Test)5; ^ test.cpp:5:7: note: candidate: Test::Test() class Test ^ test.cpp:5:7: note: candidate expects 0 arguments, 1 provided test.cpp:5:7: note: candidate: Test::Test(const Test&) test.cpp:5:7: note: no known conversion for argument 1 from ‘int’ to ‘const Test&’
-
Demo3:利用构造函数 => 编译通过
#include <iostream> using namespace std; class Test { public: Test() { } // 带一个参数的构造函数 Test(int i) { } }; int main() { Test t; t = Test(5); // 利用生成的临时对象赋值 return 0; }
-
Demo4:再次尝试 int ---> Test => 编译成功 => 为什么这里成功?
#include <ios tream> using namespace std; class Test { public: Test() { } Test(int i) { } }; int main() { Test t; t = 5; // int -> Test 成功 return 0; }
-
-
【分析】再论构造函数
-
构造函数可以定义不同类型参数
-
参数满足下列条件时成为转换构造函数
- 有且仅有一个参数
- 参数是基本类型或其它类类型(只要不是自己当前的类型即可)
-
另一个视角
- 旧式的 C 方式强制类型转换
int i; Test t; i = int(1.5); // C 方式的强制类型转换 t = Test(100); // C 方式的强制类型转换:本质是调用类的构造函数
-
编译器会尽力尝试让源码通过编译
Test t; t = 100;
- 100 这个立即数默认为
int
类型,常规上是不能赋值给Test
类的t
对象的,但当遇到转换构造函数时会发生变化! - 如果
Test
这个类中定义了转换构造函数Test(int i);
,就可以进行隐式类型转换(普通类型 ---> 类类型),默认等价于:t = Test(100);
- 100 这个立即数默认为
-
-
编译器尽力尝试的结果是隐式类型转换
- 隐式类型转换会让程序以意想不到的方式进行工作
- 隐式类型转换是工程中 bug 的重要来源
-
示例3:隐式类型转换的危害
-
Demo
#include <iostream> #include <string> using namespace std; class Test { int mValue; public: Test() { mValue = 0; } // 转换构造函数 Test(int i) { mValue = i; } // +操作符重载函数 Test operator + (const Test& p) { Test ret(mValue + p.mValue); return ret; } int value() { return mValue; } }; int main() { Test t; t = 5; // <=> t = Test(5); Test r; r = t + 10; // 这里编译通过:Test + int => r = t + Test(10); cout << r.value() << endl; // 15 return 0; }
-
编译运行
15
-
分析:代码行
r = t + 10;
编译通过,其原因是转换构造函数(Test(int i);
)的存在,从而进行了隐式类型转换,等价于:r = t + 10; => r = t + Test(10);
。而这段代码很可能是手误,极有可能造成 bug
-
-
工程中通过
explicit
关键字杜绝编译器的转换尝试-
转换构造函数被
explicit
修饰时只能进行显式转换 -
转换方式
static_cast<ClassName>(value);
: C++ClassName(value);
: C(ClassName)value;
: C,不推荐
-
示例4:转换方式
-
Demo1
#include <iostream> #include <string> using namespace std; class Test { int mValue; public: Test() { mValue = 0; } explicit Test(int i) { mValue = i; } Test operator + (const Test& p) { Test ret(mValue + p.mValue); return ret; } int value() { return mValue; } }; int main() { Test t; t = 5; Test r; r = t + 10; cout << r.value() << endl; return 0; }
-
编译
test.cpp: In function ‘int main()’: test.cpp:37:7: error: no match for ‘operator=’ (operand types are ‘Test’ and ‘int’) t = 5; ^ test.cpp:6:7: note: candidate: Test& Test::operator=(const Test&) class Test ^ test.cpp:6:7: note: no known conversion for argument 1 from ‘int’ to ‘const Test&’ test.cpp:41:11: error: no match for ‘operator+’ (operand types are ‘Test’ and ‘int’) r = t + 10; ^ test.cpp:20:10: note: candidate: Test Test::operator+(const Test&) Test operator + (const Test& p)
-
Demo2
#include <iostream> #include <string> using namespace std; class Test { int mValue; public: Test() { mValue = 0; } explicit Test(int i) { mValue = i; } Test operator + (const Test& p) { Test ret(mValue + p.mValue); return ret; } int value() { return mValue; } }; int main() { Test t; t = static_cast<Test>(5); // t = Test(5); Test r; r = t + static_cast<Test>(10); // r = t + Test(10); cout << r.value() << endl; //15 return 0; }
-
-
4 类类型 ---> 普通类型?
-
【问题】类类型是否能够类型转换到普通类型?
-
可以,利用类型转换函数
-
类型转换函数
-
C++ 类中可以定义类型转换函数
-
类型转换函数用于将类对象转换为其他类型
-
语法规则
operator Type() { Type ret; //... return ret; }
-
-
示例5:类型转换函数
-
Demo
#include <iostream> #include <string> using namespace std; class Test { int mValue; public: Test(int i = 0) { mValue = i; } int value() { return mValue; } // 类型转换函数 operator int () { return mValue; } }; int main() { Test t(100); int i = t; // <=> int i = t.operator int (); cout << "t.value() = " << t.value() << endl; // 100 cout << "i = " << i << endl; // 100 return 0; }
-
-
类型转换函数
- 与转换构造函数具有同等的地位
- 使得编译器有能力将对象转换为其他类型
- 编译器能够隐式的使用类型转换函数
-
编译器会尽力尝试让源码通过编译
Test t(1); int i = t;
t
对象为Test
类型,为什么可以用于初始化int
类型的变量:因为Test
类中定义了类型转换函数operator int();
,可以进行转换 (相当于这个对象隐式地调用类型转换函数)
5 类类型之间的转换
-
【问题】类类型之间可以相互转换么?
-
可以,类型转换函数和转换构造函数
-
示例6:
-
Demo1:利用类型转换函数
#include <iostream> #include <string> using namespace std; class Value { public: Value() { } }; class Test { int mValue; public: Test(int i = 0) { mValue = i; } int value() { return mValue; } // 类型转换函数 operator Value() { Value ret; cout << "operator Value()" << endl; return ret; } }; int main() { Test t(100); Value v = t; // <=> Value v = t.operator Value (); return 0; }
-
编译运行
operator Value()
-
Demo2:利用转换构造函数
#include <iostream> #include <string> using namespace std; class Value { public: Value() { } // 转换构造函数 Value(Test& t) { cout << "Value(Test& t)" << endl; } }; class Test { int mValue; public: Test(int i = 0) { mValue = i; } int value() { return mValue; } }; int main() { Test t(100); Value v = t; // <=> Value v = Value(t) return 0; }
-
编译运行
Value(Test& t)
-
-
类型转换函数 VS 转换构造函数
-
类型转换函数和转换构造函数同时存在时,编译器会混淆选择
-
Demo
#include <iostream> #include <string> using namespace std; class Test; class Value { public: Value() { } // 转换构造函数 Value(Test& t) { } }; class Test { int mValue; public: Test(int i = 0) { mValue = i; } int value() { return mValue; } // 类型转换函数 operator Value() { Value ret; cout << "operator Value()" << endl; return ret; } }; int main() { Test t(100); Value v = t; return 0; }
-
编译
test.cpp: In function ‘int main()’: test.cpp:40:35: error: conversion from ‘Test’ to ‘Value’ is ambiguous Value v = static_cast<Test&>(t); ^ test.cpp:27:9: note: candidate: Test::operator Value() operator Value(){ ^ test.cpp:14:9: note: candidate: Value::Value(Test&) Value(Test& t){ ^
-
改进:给
Test
类添加exlpicit
关键字#include <iostream> #include <string> using namespace std; class Test; class Value { public: Value() { } // 转换构造函数加以限制 explicit Value(Test& t) { } }; class Test { int mValue; public: Test(int i = 0) { mValue = i; } int value() { return mValue; } // 类型转换函数 operator Value() { Value ret; cout << "operator Value()" << endl; return ret; } }; int main() { Test t(100); Value v = t return 0; }
-
编译运行
operator Value()
-
-
无法抑制隐式的类型转换函数调用
-
类型转换函数可能与转换构造函数冲突
-
工程中以
Type toType()
的公有成员代替类型转换函数 -
示例:Qt 文件
-
Demo
#include <QDebug> #include <QString> int main() { QString str = ""; int i = 0; double d = 0; short s = 0; str = "-255"; //使用Type toType()公有成员函数 i = str.toInt(); d = str.toDouble(); s = str.toShort(); qDebug() << "i = " << i << endl; //-255 qDebug() << "d = " << d << endl; //-255 qDebug() << "s = " << s << endl; //-255 return 0; }
-