您的位置:首页 > 编程语言 > C语言/C++

Think_in_CPP第十二章 操作符重载(7)

2012-09-17 19:53 169 查看
12.11 自动类型转换(Automatic type conversion)

#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构造函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: