Think_in_CPP第十二章 操作符重载(7)
2012-09-17 19:53
169 查看
12.11 自动类型转换(Automatic type conversion)
输出结果
One1
Two21
可以看到Two的构造函数被调用,传入的参数是一个One对象。也就是自动类型转换发生了。发现当前类型不是所需要类型的时候,编译器试图寻找可以生成需要类型的方法。在上面的例子中需要Two类型,但是传入的是One,编译器发现Two的有一个只有一个参数构造函数,其参数类型为One于是,类型转换发生了。
要求:
1)构造函数有一个参数,且为被转换对象所属类型
2)构造函数除了被转换对象所属类型作为其中一个参数外,还有其他参数,且都提供了默认值
3)不能建立基于构造函数的用户定义类型到内建类型的自动转换,只能通过操作符重载这一方式
阻止基于构造函数的自动类型转换
方法是在构造函数前面加上关键字:explicit
通过操作符重载来实现类型自动转换(Operator conversion)
要点:
1)作为类的成员函数
2)形式:operator 目标类名()
3)在使用的时候,传入一个Four对象,但是需要的是Three对象,而Four类又有一个可用于类型转换的操作符重载函数,这个时候转换发生
Reflexivity
通过一个例子来说明成员函数方式和全局函数方式的差别
有些时候利用类型转换的特性可以带来编码的便利
利用类型转换特性加以改造
自动类型转换的陷阱
自动类型转换要注意一些问题:如一个类型到另外一个类型有1种以上的转换路径;或者是和重载函数一同使用时要转换的目标类型模糊等
问题:有两种Apple->Orange的方式
解决办法1:
解决办法2:可以提供转换函数
发生了如下事情:
1)Fo的操作符重载函数调用,返回一个Fee对象
2)Fee没有定义copy构造函数,采用默认的copy构造函数
#include <iostream> using namespace std; class One { public: int i; One() { i=1; cout << "One" << i<< endl;} }; class Two { int i; public: Two(const One& a) { i=2;cout << "Two" << i << a.i << endl;} }; void f(Two) {} int main() { One one; f(one); // Wants a Two, has a One }
输出结果
One1
Two21
可以看到Two的构造函数被调用,传入的参数是一个One对象。也就是自动类型转换发生了。发现当前类型不是所需要类型的时候,编译器试图寻找可以生成需要类型的方法。在上面的例子中需要Two类型,但是传入的是One,编译器发现Two的有一个只有一个参数构造函数,其参数类型为One于是,类型转换发生了。
要求:
1)构造函数有一个参数,且为被转换对象所属类型
2)构造函数除了被转换对象所属类型作为其中一个参数外,还有其他参数,且都提供了默认值
3)不能建立基于构造函数的用户定义类型到内建类型的自动转换,只能通过操作符重载这一方式
阻止基于构造函数的自动类型转换
方法是在构造函数前面加上关键字:explicit
class One { public: One() {} }; class Two { public: explicit Two(const One&) {} }; void f(Two) {} int main() { One one; //! f(one); // No auto conversion allowed f(Two(one)); // OK -- user performs conversion }
通过操作符重载来实现类型自动转换(Operator conversion)
class Three { int i; public: Three(int ii = 0, int = 0) : i(ii) {} }; class Four { int x; public: Four(int xx) : x(xx) {} operator Three() const { return Three(x); } }; void g(Three) {} int main() { Four four(1); g(four); g(1); // Calls Three(1,0) }
要点:
1)作为类的成员函数
2)形式:operator 目标类名()
3)在使用的时候,传入一个Four对象,但是需要的是Three对象,而Four类又有一个可用于类型转换的操作符重载函数,这个时候转换发生
Reflexivity
通过一个例子来说明成员函数方式和全局函数方式的差别
class Number { int i; public: Number(int ii = 0) : i(ii) {} const Number operator+(const Number& n) const { return Number(i + n.i); } friend const Number operator-(const Number&, const Number&); }; const Number operator-(const Number& n1, const Number& n2) { return Number(n1.i - n2.i); }
int main() { Number a(47), b(11); a + b; // OK a + 1; // 2nd arg converted to //! 1 + a; // Wrong! 1st arg not a - b; // OK a - 1; // 2nd arg converted to 1 - a; // 1st arg converted to }成员函数方式要求左值必须是确定的类型,不能通过自动转换方式得到。所以1+a处编译错误。而全局函数方式则没有这个限制1-a处,1就自动转成了需要的类型
有些时候利用类型转换的特性可以带来编码的便利
#include "../require.h" #include <cstring> #include <cstdlib> #include <string> using namespace std; class Stringc { string s; public: Stringc(const string& str = "") : s(str) {} int strcmp(const Stringc& S) const { return ::strcmp(s.c_str(), S.s.c_str()); } };
int main() { Stringc s1("hello"), s2("there"); s1.strcmp(s2); }
利用类型转换特性加以改造
#include "../require.h" #include <cstring> #include <cstdlib> #include <string> using namespace std; class Stringc { string s; public: Stringc(const string& str = "") : s(str) {} operator const char*() const { return s.c_str(); } };
int main() { Stringc s1("hello"), s2("there"); strcmp(s1, s2); // Standard C function strspn(s1, s2); // Any string function! }
自动类型转换的陷阱
自动类型转换要注意一些问题:如一个类型到另外一个类型有1种以上的转换路径;或者是和重载函数一同使用时要转换的目标类型模糊等
class Orange; // Class declaration class Apple { public: operator Orange() const; // Convert Apple to Orange }; class Orange { public: Orange(Apple); // Convert Apple to Orange }; void f(Orange) {} int main() { Apple a; //! f(a); // Error: ambiguous conversion } ///:~
问题:有两种Apple->Orange的方式
解决办法1:
class Orange {}; class Pear {}; class Apple { public: operator Orange() const; operator Pear() const; }; void eat(Orange); void eat(Pear); int main() { Apple c; //! eat(c); // Error: Apple -> Orange or Apple -> Pear ??? }
解决办法2:可以提供转换函数
class Fi {}; class Fee { public: Fee(int) {} Fee(const Fi&) {} }; class Fo { int i; public: Fo(int x = 0) : i(x) {} operator Fee() const { return Fee(i); } };
int main() { Fo fo; Fee fee = fo; }
发生了如下事情:
1)Fo的操作符重载函数调用,返回一个Fee对象
2)Fee没有定义copy构造函数,采用默认的copy构造函数
相关文章推荐
- Think_in_CPP第十二章 操作符重载(2)
- Think_in_CPP第十二章 操作符重载(4)
- Think_in_CPP第十二章 操作符重载(5)
- Think_in_CPP第十二章 操作符重载(3)
- Think_in_CPP第十二章 操作符重载(6)
- Think_in_CPP第十二章 操作符重载(1)
- Think in C++ error StreamTokenizer.cpp
- think in java第十二章读书笔记
- Think_in_CPP第十三章 动态建立对象(1)
- think in java第十二章笔记
- thinkinlamp大会后
- Think in java 答案_Chapter 2_Exercise 12
- Think in java 答案_Chapter 3_Exercise 3
- Think in java 答案_Chapter 4_Exercise 10
- 我为什么把think in java 读了10遍
- Think in java 答案_Chapter 5_Exercise 2
- Think in java中关于吸血鬼数字问题的算法
- Think in java 答案_Chapter 6(二)
- Think in UML笔记第1章--为什么要UML
- think in java中的初始化,final,static,继承