数据类型转换和运算符重载
一、数据类型转化(data type conversion)
目的对象中的例程 | 源对象中的例程 | |
基本类型—>基本类型 | 内置的转换运算符 | |
基本类型—>用户自定义类型 | 构造函数 | N/A |
用户自定义类型—>基本类型 | N/A | 转换运算符 |
用户自定义—>用户自定义 | 构造函数 | 转换运算符 |
下面我们通过具体的实例来理解上表的含义:
1.用户自定义<—>基本类型
#include <iostream> using namespace std; ////////////////////////////////////////////////////////////////////////// class Distance { private: const float MTF; int feet; float inches; public: Distance():feet(0),inches(0.0),MTF(3.28F) {} Distance(float meters):MTF(3.28F) { float fi=meters*MTF; feet=int(fi); inches=12*(fi-feet); } Distance(int ft,float in):feet(ft),inches(in),MTF(3.28F) {} void getdist() { cout<<"Enter the feet:";cin>>feet; cout<<"Enter the inches:"; cin>>inches; } void showdist() { cout<<feet<<"\'"<<"-"<<inches<<"\""<<endl; } operator float () const { float ff=inches/12; ff+=static_cast<float>(feet); return ff/MTF; } }; ////////////////////////////////////////////////////////////////////////// int main() { float meter; Distance dist1=2.35F; //uses 1-arg constructor to //convert meters to Distance cout<<"dist1= ";dist1.showdist(); meter=static_cast<float>(dist1); //uses conversion operator(explicit) //for Distance to meters cout<<"dist1= "<<meter<<" meters"<<endl; Distance dist2(5,10.25); meter=dist2; //also uses conversion op(implicit) cout<<"dist2= "<<meter<<" meters"<<endl; //dist2=meter; //**error: = won't convert // return 0; }
从上面我们可以看出:基本类型—>用户自定义 用单参数的构造函数(转换构造函数conversion constructor)
用户自定义—>基本类型 用转换运算符(conversion operator)
2.c字符串与String对象之间的转换
#include <iostream> #include <string.h> using namespace std; //////////////////////////////////////////////////////////////////////// class String { private: static const int SZ=80; char str[SZ]; public: String() { str[0]='\0'; strcpy(str,""); } String(char s[]) { strcpy(str,s); } void display() const { cout<<str; } operator char* () { return str; } }; //////////////////////////////////////////////////////////////////////// int main() { String s1; char xstr[]="nihao,haha!"; s1=xstr; //为什么这里又能够转换了 s1.display(); String s2="Bonne Annee!"; cout<<static_cast<char*>(s2); //use conversion operator(explicit) cout<<endl; return 0; }
1)上面注释:为什么这里能转换,对比的是上一个程序中的dist2=meter; 两者都是从基本类型转化为用户自定义类型,但是为什么一个可以一个不可以呢?
答:
2)第二句注释的地方告诉我们:转换不仅发生在赋值语句中,在其他适合的场合也会发生,如传递给运算法(如<<)或者函数的参数中。
3)在这里如果有一句:xstr=s2;(把用户自定义类型—>基本类型)对不对呢?
答案是不行的,因为c字符串是一个数组,s2为了传给xstr会首先调用转换运算符 char*,但是他返回的是 一个数组的首地址,在这里我们会想到数组是不能以通常的方式(=)给另一个数组赋值的。
二、关键字explicit和mutable
1.explicit是用来防止转换的
阻止转换运算符的执行的转换比较容易:不定义运算符就可以了。不过如果牵扯到构造函数,事情就不那么简单了。
例子:
/************************************************************************/ /* explicit.cpp /************************************************************************/ #include <iostream> using namespace std; class Distance { private: const float MTF; int feet; float inches; public: Distance():feet(0),inches(0.0),MTF(3.28F) {} explicit Distance(float meters):MTF(3.28F) { float fi=meters*MTF; feet=int(fi); inches=12*(fi-feet); } void getdist() { cout<<"Enter the feet:";cin>>feet; cout<<"Enter the inches:"; cin>>inches; } void showdist() { cout<<"the distance is:"<<feet<<"\'"<<inches<<"\""; } }; void functiond(Distance dd) { dd.showdist(); } int main() { float meters=2.0F; Distance d1; Distance d2(2.3F); //Distance d3=2.3F; //functiond(meters); return 0; }
显示构造函数的副作用就是,不能使用带有等号的对象初始化形式。 在函数调用的时候,也牵扯到一个从meters到dd转化过程,而此过程是隐式的所以编译器也会报错。2)使用mutable可以改变const对象的数据
/************************************************************************/ /* multab.cpp /************************************************************************/ #include <iostream> using namespace std; class scrollbar { public: scrollbar(int si,string own):size(si),owner(own) {} void setsize(int siz) const { size=siz; } void setowner(string str) /*const*/ { owner=str; } int getsize() const { return size; } string getowner() const { return owner; } private: /*mutable */int size; mutable string owner; }; int main() { const scrollbar ss(122,"windows"); ss.setsize(100); //错误,const对象只能调用const成员函数,因为没有mutable不能修改 ss.setowner("linux"); //错误,const对象只能调用const成员函数,即便owner前有mutable。 ss.getowner(); ss.getsize(); return 0; }
因此我们要向改变const对象的数据必须具备两个条件:首先,const对象的成员函数是const类型的;其次,定义的数据成员必须要有mutable的前缀。