输入带有空格的字符串
cin.getline(a[i])
运算符重载的语法
-
定义一个重载的运算符与定义一个函数类似,只是这个函数的名称必须以operator开头。
运算符重载函数的一般形式为:
类型 类名::operator 重载的运算符(参数表)
{
函数体
}
参数的个数由以下两个因素决定:
- 该操作符是一元操作符还是二元操作符。
- 重载为成员函数还是友元函数。
运算符重载的两种形式
运算符重载函数是如何调用的?
运算符重载函数作为类的成员函数
成员运算符重载函数在类中的声明格式为:
class X
{ ……
<返回数据类型> operator <运算符> (<参数表>);
……
};
成员运算符重载函数在类外定义的格式为:
<返回数据类型> X:: operator <运算符> (<参数表>)
{
<函数体>
}
举例:
class CComplex
{
public:
CComplex(double r=0.0,double i=0.0){real=r,imag=i;}
void print() const;
CComplex operator++(); //前缀
CComplex operator++(int); //后缀
CComplex operator--(); //前缀
CComplex operator--(int); //后缀
};
常对象
运算符重载的限制
- 只能重载已经存在的C++运算符
- 运算符重载不能改变运算符操作数的个数,优先级和结合性
- 运算符的操作数必须至少有一个某个类的类对象,否则不能对运算符进行重载
- 重载运算符不可以使用缺省参数;
- 除了赋值运算符 = 外,重载运算符可由派生类继承下去;
- 下列运算符不能重载: :: .* . ?: sizeof
运算符重载函数作为友元函数
- 运算符重载函数可以用友元函数的形式来实现。
- 函数参数的个数与运算符原有操作数个数相同
- 第一个参数表示左操作数
- 第二个参数表示右操作数
- 第一个参数类型为类对象的引用
- 赋值运算符‘=’、下标运算符‘[]’、成员选择运算符‘->’和函数调用运算符‘()’等不能用友元函数形式重载
友元运算符重载函数在类中的声明格式为:
class X
{ ……
friend <返回数据类型> operator <运算符> (<参数表>);
……
};
友元运算符重载函数在类外定义的格式为:
<返回数据类型> operator <运算符> (<参数表>)
{
<函数体>
}
重载为成员函数与重载为友元函数的比较
“+”重载为成员函数
CComplex CComplex::operator+(const CComplex& c)
{
return CComplex(real+c.real, image+c.image);
}
“+”重载为友元函数
CComplex operator+(const CComplex& c1,const CComplex& c2)
{
return Complex(c1.real+c2.real, c1.image+c2.image);
}
运算符重载应用
- 以下运算符经常需要重载:
1.算术运算符 2.关系运算符
3.逻辑运算符 4.赋值运算符
5.下标运算符 6.函数调用运算符
特殊运算符的重载
= 运算符的重载
class Complex
{
public:
Complex(double r=0.0,double i=0.0){real=r,imag=i;}
void display();
Complex& operator=(const Complex& r_c);
};
【*如果类没有定义赋值运算符重载函数,则编译程序会提供缺省的赋值运算符,就是将赋值运算符右边对象的数据域复制给其左边对象的数据成员。】
注意:分配空间
重载下标运算符“[ ]”
- 下标运算符“[ ]”用来取某个向量的某个元素,或直接对向量中某个元素赋值,它被视为一个二元运算符。
- 下标运算符只能作类成员运算符进行重载,不可作为友元运算符。
- 重载下标运算符的最大好处是提供一种向量访问的安全方法。
重载()运算符
- 函数调用运算符”()”可以看作一个双目运算符,它的两个操作数分别为函数名和函数参数列表。 f (x,y) f ()
- 函数调用运算符只能采用非静态的成员函数重载。
- 函数调用运算符重载可以不带或带任意个参数。
举例
数学函数的抽象:f(x,y) = 2x+y
class Function {
public:
double operator() (double x, double y) const
{
return 2*x+y;
}
};
int main( ){
Function fun;
cout << fun(1.5, 2.2) << endl;
return 1;
}
new和delete的重载
例:重载new和delete运算符。
#include <iostream>
using namespace std;
#include <stddef.h>
class memmanager{
public:
memmanager(){cout<<"default constructor"<<endl;}
void *operator new(size_t size);
//分配一块大小为size的内存
void *operator new(size_t size,char tag);
//分配一块大小为size的内存,并且用字符tag赋值
void operator delete(void *p);
//释放指针p所指向的一块内存空间
};
void *memmanager::operator new(size_t size)
{
cout<<"new1 operator"<<endl;
char *s=new char[size]; //分配大小为size的内存空间
*s='a'; //用字符'a'赋值
return s; //返回指针
}
void *memmanager::operator new(size_t size,char tag)
{
cout<<"new2 operator"<<endl;
char *s=new char[size];
*s=tag; //用字符tag赋值
return s; //返回指针
}
void memmanager::operator delete(void *p)
{
cout<<"delete operator"<<endl;
char *s=(char *)p; //强制类型转换
delete[] s; //释放内存空间
}
void main()
{
memmanager *m=new memmanager();
delete m;
memmanager *m1=new('B') memmanager();
delete m1;
}
类型之间的转换
C++语言允许的类型转换有4种:
- 标准类型->标准类型。
- 标准类型->类类型。
- 类类型->标准类型。
- 类类型->类类型。
【标准类型是除class,struct和union类型外的其他所有类型】
对于标准类型,C++语言提供了两种类型转换:
- 隐式类型转换。
- 显式类型转换。
举例:
自定义类对象的输入输出
- 插入运算符<< 和 抽取运算符>>的重载
- 重载插入和抽取运算符只能用访问类的私有成员的友元函数来实现,因为插入和抽取运算符为双目运算符,且运算符的左操作数为流,右操作数为类对象,因而插入和抽取运算符的重载不能以类成员函数形式出现
举例:
class CComplex //复数类声明
{
double real;
double image;
public:
CComplex(double r=0.0,double i=0.0):real(r),image(i){}
friend ostream& operator<<(ostream& stream, CComplex &obj);
friend istream& operator>>(istream& stream, CComplex &obj);
};
//注意:在oj上,往往需要
// friend ostream& operator<<(ostream& stream, const Complex &obj);
ostream& operator<<(ostream& stream, CComplex &obj)
{
if (obj.image < 0)
stream<< obj.real << obj.image << "i"<<endl;
else if (obj.image > 0)
stream << obj.real << "+" << obj.image << "i"<<endl;
else
stream << obj.real << endl;
return stream;
}
istream& operator>>(istream& stream, CComplex &obj)
{
stream>>obj.real;
stream>>obj.image;
return stream;
}
int main()
{
CComplex obj;
cin>>obj;
cout<<obj;
return 1;
}