重载流插入运算符"<<“和流提取运算符”>>"
- C++编译系统已经对"<<“和”>>"进行了重载,使之作为流插入运算符和流提取运算符,能用来输入和输出C++标准类型的数据。
- 对于自己定义的类型的数据(如类对象),是不能直接用"<<“和”>>"来输出和输入的。如果想用它们输出和输入自己声明的类型的数据,必须对它们重载。
- 对"<<“和”>>"重载的函数形式如下:
istream & operator>>(istream &,自定义类 &);
ostream & operator<<(ostream &,自定义类 &);
重载运算符">>“的函数的第1个参数和函数的类型都必须是istream&类型(即istream类对象的引用),第2个参数是要进行输入操作的类;重载运算符”<<"的函数的第1个参数和函数的类型都必须是ostream&类型(即ostream类对象的引用),第2个参数是要进行输入操作的类。
- 只能将重载">>“和”<<"的函数作为友元函数,而不能将它们定义为成员函数。
重载流插入运算符"<<"
例:用重载运算符"<<"输出复数
#include<iostream>
using namespace std;
class Complex
{
public:
Complex() { real = 0; imag = 0; }
Complex(double r, double i) { real = r; imag = i; }
Complex operator+(Complex& c2); //运算符"+"重载为成员函数
friend ostream& operator<<(ostream&, Complex&); //运算符"<<"重载为友元函数
private:
double real;
double imag;
};
Complex Complex::operator+(Complex& c2) //定义运算符"+"重载函数
{
return Complex(real + c2.real, imag + c2.imag);
}
ostream& operator<<(ostream& output, Complex& c) //定义运算符"<<"重载函数
{
output << "(" << c.real << " + " << c.imag << "i)" << endl;
return output;
}
int main()
{
Complex c1(2, 4), c2(6, 10), c3;
c3 = c1 + c2;
cout << c3;
return 0;
}
//运行结果:
(8 + 14i)
程序分析:
- return output的作用是能连续向输出流插入信息。output是ostream类的对象的引用(它是实参cout的引用,或者说output是cout的别名),cout通过传送地址给output,使它们二者共享同一段存储单元,因此,return output就是return cout,将输出流cout的现状返回,即保留输出流的现状。
重载流插入运算符">>"
#include<iostream>
using namespace std;
class Complex
{
public:
friend ostream& operator<<(ostream&, Complex&); //声明友元重载运算符"<<"函数
friend istream& operator>>(istream&, Complex&); //声明友元重载运算符">>"函数
private:
double real;
double imag;
};
ostream& operator<<(ostream& output, Complex& c) //定义重载运算符"<<"函数
{
output << "(" << c.real << " + " << c.imag << "i)";
return output;
}
istream& operator>>(istream& input, Complex& c) //定义重载运算符">>"函数
{
cout << "input real part and imaginary part of complex number:";
input >> c.real >> c.imag;
return input;
}
int main()
{
Complex c1, c2;
cin >> c1 >> c2;
cout << "c1=" << c1 << endl;
cout << "c2=" << c2 << endl;
return 0;
}
程序分析:
- cin语句中有两个">>",每遇到一次">>“就调用一次重载运算符”>>"的函数,因此,两次输出提示输入的信息,然后要求用户输入对象的值。
运行结果:
有关运算符重载的归纳
- C++中,运算符重载使类的设计更加丰富多彩,扩大了类的功能和适用范围,使程序易于理解,也易于对对象进行操作,体现了为用户着想、方便用户使用的思想。有了运算符的重载,在声明了类之后,我们就可以把用于标准类型的运算符用于自己声明的类,类的声明是一劳永逸的,有了好的类后,用户在程序中就不必定义许多成员函数去完成某些运算和输入输出的功能,使主函数更加简单易读。好的运算符重载能体现面向对象的程序设计思想。
- 使用运算符重载的具体做法是:
①要先确定重载的是哪一个运算符,以及要将它作用于哪个类,重载运算符只能把一个运算符用于一个指定的类。
②设计运算符重载函数和有关的类(在该类中包含运算符重载成员函数或友元函数重载函数)。函数的的功能完全是由设计者指定,目的是实现用户对使用运算符的要求。
③在实际工作中,一般并不要求最终用户自己编写每一个运算符重载函数,往往是有人事先把本领域或本单位工作中需要用重载的运算符统一编写好一批运算符重载函数,把它们集中放在一个头文件中(文件名自定),放在指定的文件目录中,提供给有关的人使用。
④使用者需要了解在该头文件包含哪些运算符的重载,适用于哪些类,有哪些参数。也就是要了解运算符的重载函数的原型。
⑤如果有特殊的需要,并无现成的重载运算符可用,就需要自己设计运算符重载函数。应当注意把每次设计的运算符重载函数保留下来,以免下次用到时重新设计。 - 在运算符重载中使用引用的重要性:利用引用作函数的形参可以在调用函数的过程中不用传递值的方式进行虚实结合,而通过传址方式使形参成为实参的别名,而不必设置一个形参来存放实参传递过来的值,因此减少了时间和空间的开销。此外,如果重载函数的返回值是对象的引用时,返回的不是常量,而是引用所代表的对象,它可以出现咋赋值号的左侧而成为左值,可以被赋值或参与其他操作。
不同类型数据间的转换
标准类型数据间的转换
- 在C++中,某些不同数据类型之间可以自动转换,例如:
int i = 6;
i = 7.5 + i;
这种转换是由C++编译系统自动完成的,用户无须干扰。这种转换称为隐式类型转换。
- C++还提供显示类型转换,其形式为:
类型名(数据)
;在C语言中采用的形式为:(类型名)数据
用转换构造函数进行不同类型数据的转换
-
转换构造函数的作用是将一个其他类型的数据转换成一个类的对象。
-
默认构造函数:函数原型的形式为:
Complex(); //没有参数
-
用于初始化的构造函数:函数原型的形式为:
Complex(double r,double i); //形参表列中一般有两个以上参数
-
用于复制对象的复制构造函数:函数原型的形式为:
Complex(Complex &c); //形参是本类对象的引用
-
转换构造函数:转换构造函数只有一个形参,如:
Complex(double r) { real = r; imag = 0; }
其作用是将double型的参数r转换成Complex类的对象,将r作为复数的实部,虚部为0。
注意:转换构造函数只能有一个参数。如果有多个参数的,它就不是转换构造函数。
归纳起来 ,使用转换构造函数将一个指定的数据转换为类对象的方法如下:
- 先声明一个类
- 在这个类中定义一个只有一个参数的构造函数,参数的类型是需要转换的类型,在函数体中指定转换的方法
- 在该类的作用域内可以用以下形式进行类型转换:
类名(指定类型的数据)
,就可以将指定类型的数据转换为此类的对象
类型转换函数
- 类型转换函数的作用是将一个类的对象转换成另一类型的数据。
- 类型转换函数的一般形式为:
operator 类型名()
{ 实现转换的语句 }
在函数名前面不能指定函数类型,函数没有参数。其返回值的类型是由函数名中指定的类型名来确定的。类型转换函数只能作为成员函数,因为转换的主体是本类的对象。不能作为友元函数或普通函数。
例:将一个double数据与Complex类数据相加
#include<iostream>
using namespace std;
class Complex
{
public:
Complex() { real = 0; imag = 0; }
Complex(double r, double i) { real = r; imag = i; }
operator double() { return real; } //定义类型转换函数
private:
double real;
double imag;
};
int main()
{
Complex c1(3, 4), c2(5, -10), c3; //建立3个Complex类对象
double d;
d = 2.5 + c1; //要求将一个double数据与Complex类数据相加
cout << d << endl;
return 0;
}
//运行结果:5.5
重载函数都使用关键字operator,它的意思是"运算符"。因此,通常把类型转换函数也称为类型转换运算函数,由于它也是重载函数,因此也称为类型转换运算符重载函数(或称强制类型转换运算符重载函数)
例:包含转换构造函数、运算符重载函数和类型转换函数的程序
#include<iostream>
using namespace std;
class Complex
{
public:
Complex() { real = 0; imag = 0; } //默认构造函数,无形参
Complex(double r) { real = r; imag = 0; } //转换构造函数,一个形参
Complex(double r, double i) { real = r; imag = i; }//实现初始化的构造函数,两个形参
friend Complex operator+(Complex c1, Complex c2); //重载运算符"+"的友元函数
void display();
private:
double real;
double imag;
};
Complex operator+(Complex c1, Complex c2) //定义运算符"+"重载函数
{
return Complex(c1.real + c2.real, c1.imag + c2.imag);
}
void Complex::display() //定义输出函数
{
cout << "(" << real << "," << imag << "i)" << endl;
}
int main()
{
Complex c1(3, 4), c2(5, -10), c3; //建立3对象
c3 = c1 + 2.5; //复数与double数据相加
c3.display();
return 0;
}
//运行结果:(5.5,4i)
在已定义了相应的转换构造函数情况下,将运算符"+"函数重载为友元函数,在进行两个复数相加时,可以使用交换律。如果运算符"+"重载函数不作为Complex类的友元函数,而作为Complex类的成员函数,不能得到同样的结果。
总结:
-
如果运算符函数重载为成员函数,它的第1个参数必须是本类的对象。当第1个操作数不是类对象时,不能将运算符函数重载为成员函数。如果将运算符"+"函数重载为类的成员函数,交换律不适用
由于这个原因,一般情况下将双目运算符函数重载为友元函数。单目运算符则多重载为成员函数。 - 如果一定要将运算符重载为成员函数,而第1个操作数又不是类对象时,只有一个办法能解决,再重载一个运算符"+"函数。当然此函数只能是友元函数,显然这样做不太方便。