今天学习了各种运算符重载,让类更易于使用。在编写管理资源的类时(如动态数组或字符串),除了析构函数外,还需要至少提供复制构造函数和复制赋值运算符。还学习了用户自定义的字面量,以通过一个后缀来标识字面量是什么类型。
目录
1. 单目运算符
就是只对一个操作数进行操作的运算符。
1.1 单目递增与单目递减运算符
单目运算符没有参数,它们使用的唯一参数是当前实例(*this)。
语法如下:
Date& operator ++()//前缀递增运算符
{
//balabala
return *this; //返回当前实例
}
Date& operator ++(int)//后缀递增运算符
{
Date copy(*this);
//balabala
return copy;
}
注意:int参数仅仅是为了区分前缀和后缀运算符,是一种标准规定。
1.2 转换运算符
将类对象转换成cout能够接受的类型,可以添加一个const char*的运算符。
语法如下:
operator const char*()
{
//balabala
}
2. 双目运算符
就是对两个操作数进行操作的运算符。
定义如下:
//以全局函数或静态成员函数的方式实现的双目运算符定义
return_type operator_type (parameter1, parameter2);
//以类成员的方式实现的双目运算符的定义
return_type operator_type(parameter);
2.1 双目加法与双目减法
Date operator+ (int dayToAdd)
{
Date newDate(month, day + dayToAdd, year);
return newDate;
}
Date operator-(int dayToSub)
{
return Date(month, day - dayToSub, year);
}
2.2 重载等于运算符和不等于运算符
定义如下:
bool operator==(const ClassType& compareTo)
{
//balabala
}
bool operator!=(const ClassType& compareTo)
{
//balabala
}
2.3 重载复制赋值运算符(=)
classType& operator=(const classType& copySource)
{
if(this != ©Source)
{
//Balabala
}
return *this;
}
如果类封装了原始指针,那么要确保赋值时进行深复制,应当定义复制赋值运算符。
示例如下:
Date& operator=(const Date& copySource)
{
if((this != ©Source) && (copySource.buffer != NULL))
{
if(buffer!=NULL)
{
delete[] buffer;
}
buffer = new char[strlen(copySource.buffer) + 1];
strcpy(buffer, copySource.buffer);
}
}
以上代码首先检查源和目标是否同一对象,如果不是则释放成员buffer内存,在重新给它分配足以储存复制源中文本的内存,然后使用strcoy()进行复制。
2.4 下标运算符
下标运算符能够让我们像访问数组一样访问类中的动态数组。
示例如下:
const char& operator[] (int index) const
{
if(index<strlen(buffer))
{
return buffer[index];
}
}
小结1的完整代码段:
class Date
{
private:
int day, month, year;
string dateInString;
char* buffer;
public:
Date(int inMonth, int inDay, int inYear): month(inMonth), day(inDay), year(inYear){}
~Date()
{
if(buffer!=NULL)
{
delete[] buffer;
}
}
Date& operator ++()//前缀递增运算符
{
//balabala
++day;
return *this; //返回当前实例
}
Date& operator --()
{
--day;
return *this;
}
Date& operator ++(int)//后缀递增运算符
{
Date copy(*this);
//balabala
day++;
return copy;
}
Date& operator --(int)
{
Date copy(*this);
day--;
return copy;
}
operator const char*()//转换运算符
{
ostringstream formattedDate;
formattedDate<<month<<" / "<<day<<" / "<<year<<endl;//formattedDate将整型成员转换为string对象
dateInString = formattedDate.str();
return dateInString.c_str();
}
Date operator+ (int dayToAdd)
{
Date newDate(month, day + dayToAdd, year);
return newDate;
}
Date operator-(int dayToSub)
{
return Date(month, day - dayToSub, year);
}
void operator+=(int daysToAdd)
{
day+=daysToAdd;
}
void operator-=(int daysToAdd)
{
day-=daysToAdd;
}
bool operator==(const Date& compareTo)
{
//balabala
return((day==compareTo.day)&&(month == compareTo.month)&&(year==compareTo.year));
}
bool operator!=(const Date& compareTo)
{
//balabala
return !(this->operator==(compareTo));
}
Date& operator=(const Date& copySource)
{
if((this != ©Source) && (copySource.buffer != NULL))
{
if(buffer!=NULL)
{
delete[] buffer;
}
buffer = new char[strlen(copySource.buffer) + 1];
strcpy(buffer, copySource.buffer);
}
}
const char& operator[] (int index) const
{
if(index<strlen(buffer))
{
return buffer[index];
}
}
};
3. 用户定义的字面量
在实际的开发过程中,我们会经常使用到结构体来表示一个新的类型。那么在遇到结构体类型都数据进行运算时,只能先依次定义,然后进行运行。这在测试环节会非常的繁琐,为此C++11标准增加了可以通过后缀表示的操作符来将字面量转换为需要的类型。
以下为自定义热力学单位的示例:
struct Temperature
{
/* data */
double Kelvin;
Temperature(long double kelvin): Kelvin(kelvin){}
};
Temperature operator"" _C(long double celcius)//用户定义自变量_F以声明一个华氏温度值
{
return Temperature(celcius +273);
}
Temperature operator"" _F(long double fahrenheit)//用户定义自变量_C以声明一个摄氏温度值
{
return Temperature((fahrenheit + 459.67) * 5 / 9);
}
int main()
{
Temperature k1 = 31.73_F;
Temperature k2 = 0.0_C;
cout << "K1 is "<<k1.Kelvin<<" kelvin"<<endl;
cout <<"K2 is "<<k2.Kelvin<<" kelvin"<<endl;
return 0;
}
结果如下: