一个简单的string类——自动转换——Str操作——有些转换是危险的——类型转化操作函数——类型转换与内存管理——
一个简单的string类
通常情况下,一个不需要析构函数的类也不需要显示的定义复制构造函数或赋值运算符函数。
自动转换
C++自带的类型变量之间可以自动进行转换。例如:
double d=10; //将10转换成double类型并用于初始化double变量d
double d2;
d2=10; //将10转换成double类型并将它赋给double变量d2;
用户定义的转换(user-defined conversion):用户定义的转换定义了如何将一个其他类型转换成该类对象,以及反过来的操作。与C++自带的转换一样,编译器在使用用户定义的转换时会将一个值转换成程序需要的类型。
在类中定义类型转换包含两个方面的定义:将其他类型转换成该类类型,或者将该类类型转换成其他类型。而第一种可通过定义一个只带有一个参数的构造函数定义类型转换。
Str操作
“>>”,”<<”,”s[i]”,”s1+s2”都是二元运算符。如果我们将他们定义成为函数,每个函数都应该有两个参数,如果被定义的是一个成员函数,那么其中一个参数可以是隐式被提供的(如第11章所述)。
输入和输出运算符
对于二元运算符函数来说,其左操作数必须作为函数的第一个参数,有操作数必须作为函数的第二个参数。如果该运算符函数是成员函数,那么第一个参数(也就是左操作数)总是会默认的传递给该成员函数。
由之前的理论:判断一个函数为成员函数,就是判断他是否会改变对象状态。那么输入、出运算符会改变对象状态,照此应该作为成员函数,但是由于我们没有权限更改istream的权限,而且如果作为成员函数会将输入、出的书写形式将与库的语法规则不同。因此。输入和输出函数不能作为类的成员函数。
友元函数
友元函数:友元函数拥有与成员函数相同的访问能力。通过将输入运算符函数声明为Str类的友元函数,我们赋予了该函数与类的成员函数一样的对Str类私有成员的读写能力。
友元函数的声明可以加在类定义的任何地方:将他加在一个private标识后面与加在一个public标识后面没有任何区别。由于友元函数具有特殊的访问权利,因此它是类接口的一部分。也正是因为如此,一般在类声明的前面,Public接口的附近,会将全部友元函数的声明放在一起作为一个相对独立的组。
设计二元运算符
在二元运算符的设计中,参数转换的地位很重要。如果一个类支持转换,那么将二元运算符定义成非成员函数是一个很好的习惯。这样就可以保证两个操作数的对称性。
如果一个运算符函数是类的成员函数,那么这个运算符的左操作数不能是自动转换得到的结果。
对于非成员运算符函数的左操作数以及全部运算符函数的右成员函数来说,都遵循与一般函数的参数相同的规律:操作数可以是任何一种能被转换成参数指定类型的类型。
通常是希望两个操作数是完全对称的,这就要求我们将运算符函数定义成一个非成员函数。
有些转换是危险的
通常情况,我们总是将定义对象的结构的构造函数声明为explicit。有些构造函数的参数最后会变成对象的一部分,这些构造函数一般就不必要被声明为explicit。
类型转换操作函数
转换操作函数的函数名为operator加上目标类型名。类的编写者可以定义显示的类型转换操作,该操作定义了如何将一个对象从原来的类型转换成一个希望得到的类型。例如:如果有一个类有一个名为operator double的成员函数,这个成员函数可以用于将一个该类类型的变量转换成double类型的变量。
转换操作函数在将一个自定义类型转换成一个C++内建的类型时经常被调用,有时候也可以用他将一个类的类型转换成另一个我们没有代码类的类型。我们都不能往目标类中加入构造函数,只能在我们拥有代码的类中将转换函数定义成类的一部分。
一个指向void的指针有时候又被称为通用指针,这是一个可以指向任何类型对象的指针。
标准库允许将一个istream类型用作一个判断条件表达式,但是不能将它作为算术值使用。
类型转换与内存管理
在没有explicit关键字声明的情况下,非常量版本的任意类型可以隐式的转换为常量版本的该类型的引用。例如:
int a=4;
const int &b=a; //隐式转换
*作为类成员的模板函数:类可以将模板函数作为成员函数。这种类本身可以是模板类,也可以不是。一个拥有模板成员函数的类相当于拥有许多同名的成员函数。类的模板成员函数的声明方法与定义方法与其他的模板函数一样。