1、成员函数和全局函数(友元函数)转换的技巧
从类的成员函数转换为全局函数,只需要加一个this指针;
从全局函数转换为类的成员函数,需要减去一个左操作数参数。
【友元函数、成员函数】唯一的区别:
友元函数中没有this指针,而成员函数中有this————>因此友元函数的参数要比成员函数的参数多一个。
【技巧】
友元函数的多出来的参数相当于成员函数中隐藏的this指针指向的对象*this,例如:
friend String operator+(const String& s1,const String& s2); //s1的作用
String operator+(const String& s); //相当于成员函数中的*this
friend String operator+(const String& s,const char* str);//s的作用
String operator+(const char* str); //相当于成员函数中的*this
friend String operator+=(String& s1, const String& s2); //s1的作用
String operator+=(const String& s);//相当于成员函数中的*this
friend String operator+=(String& s,const char* str);//s的作用
String operator+=(const char* str);//相当于成员函数中的*this
2、友元函数
//详细讲解:operator+函数的返回值是对象?还是对象的引用?以及各自对应的正确写法!
#include <iostream>
using namespace std;
class Complex
{
public:
Complex(double r=0,double i=0) {real=r;imag=i;}
//重载函数作为友元函数
//形式1:错误
friend Complex& operator+(Complex &c1,Complex &c2) //【此处代码是错误的】返回的是引用Complex&
{
Complex tmp;
tmp.real = c1.real+c2.real;
tmp.real = c1.imag+c2.imag;
return tmp;
//返回一个临时对象的简写:return Complex(c1.real+c2.real, c1.imag+c2.imag);
可以修改成:在被调函数中动态给对象分配空间,这样可以把结果甩出去
// Complex *tmp = new Complex;
// tmp->real = c1.real+c2.real;
// tmp->real = c1.imag+c2.imag;
// return *tmp;
}
//分析形式1为什么错误? 答:因为返回值为对象的引用时,返回的内容如果是临时对象,在函数
//执行结束后,临时对象被析构,因此返回一个无效的值。
//形式2:正确
friend Complex operator+(Complex &c1,Complex &c2) //【此处代码是正确的】返回的是对象Complex
{
Complex tmp;
tmp.real = c1.real+c2.real;
tmp.real = c1.imag+c2.imag;
return tmp;
//返回一个临时对象的简写:return Complex(c1.real+c2.real, c1.imag+c2.imag);
}
//分析形式2为什么正确? 答:因为返回值为对象时,“调用时operator+(c1,c2);返回的
//内容也是临时对象”,但是返回时会调用拷贝构造函数另外创建一个对象来保存临时对象tmp的
//值,因此尽管在函数执行结束后,临时对象被析构,但是拷贝构造出来的对象可以返回给主函
//数,被主函数中的对象接受。
void display()
{
cout<<"real="<<real<<","<<"imag="<<imag<<endl;
}
private:
double real;
double imag;
};
int main( )
{
Complex c1(3,4),c2(5,1),c3;
c3=c1+c2;
c1.display();
c2.display();
c3.display();
}
3、运算符重载
注:
不能重载的运算符有 . .* sizeof :: ?:
常用的重载运算符有 [] = ++ – == !=
C++中不能用友元函数重载的运算符有: = ( ) [ ] ->
#include <iostream>
using namespace std;
class Complex
{
public:
//构造函数:写成下面三个,看起来啰嗦,其实是为了防止调用时发生二义性
Complex(){real=0; imag=0;}
Complex(double r,double i) {real=r;imag=i;}
Complex(double r){real=r;imag=0;} //转换构造函数
/*-------------------------------------------------------------------*/
//重载 +
//case1:重载运算符函数为成员函数(左操作数由this指针传递,右操作数由参数传递)
Complex operator-(Complex & obj) //返回类型Complex
{
Complex tmp;
tmp.real = real+obj.real;
tmp.imag = imag+obj.imag;
return tmp;
}
//case2:重载运算符函数为友元函数(左、右操作数由参数传递)
friend Complex operator+(const Complex& c1,const Complex& c2) //返回类型Complex
{
return Complex(c1.real+c2.real, c1.imag+c2.imag);
}
/*-------------------------------------------------------------------*/
//重载前置++、--
Complex& operator--() //成员函数
{
return Complex(--real,--imag); // 返回类型都是引用Complex&
}
friend Complex& operator++(Complex& obj) //友元函数
{
return Complex(++obj.real,++obj.imag); //形参和返回类型都是引用Complex&
}
//重载后置++、--
Complex operator++(int) //成员函数
{
Complex tmp = *this;
this->real++;
this->imag++;
return tmp;
}
friend Complex operator--(Complex& obj,int) //友元函数
{
Complex tmp = obj;
obj.real--;
obj.imag--;
return tmp;
}
/*-------------------------------------------------------------------*/
//重载 <<
friend ostream& operator<<(ostream& out,Complex& obj)
{
out<<"real="<<obj.real<<","<<"imag="<<obj.imag;
return out;
}
//friend void operator<<(ostream& out,Complex& obj) //这样不能连续输出
//{
// out<<"real="<<obj.real<<","<<"imag="<<obj.imag;
//}
//【疑问】为什么返回值是ostream& ,而不是void?
//【答】为了能够连续的输出; || 注:函数返回值当作左值,则必须返回一个引用!
/*-------------------------------------------------------------------*/
private:
double real;
double imag;
};
int main()
{
Complex c1(3,4),c2(5),c3;
c3 = c1 + c2;
//cout<<c1;//等价于operator<<(cout,c1);,调用完成后,返回值为cout,可以作为左值继续输出!
cout<<c1<<endl; //等价于operator<<(operator<<(cout,c1),c1);
cout<<c2<<endl;
cout<<c3<<endl;
c3 = 20 + c3; //这种情况必须用友元函数
cout<<c3<<endl;
c3--;
cout<<c3<<endl;
}
【总结规律】
//【返回类型:对象Complex、String】
① + - * / % += -= *= /= %= 基本的四则运算
friend String operator+(const String& s1,const String& s2);
String operator+(const String& s);
friend String operator+(const String& s,const char* str);
String operator+(const char* s);
friend String operator+=(String& s1, const String& s2);
String operator+=(const String& s);
friend String operator+=(String& s,const char* str);
String operator+=(const char* str);
②单目运算符:后置++、后置--
Complex operator++(int);
friend Complex operator--(Complex& obj,int);
------------------------------------------------------------------------
//【返回类型:对象的引用Complex&、String&】
Complex& operator--();//前置++、前置--
①连续操作:>> 、 << 、 赋值=
friend ostream& operator<<(ostream& out,Complex& obj);
Complex& operator=(const Complex& obj);
②返回值作为“左值”
char& operator[](int i); // []操作符
========================================================================================
【综合示例】
//String类
//-------------------------------------------------------------------
//重载 = :返回的是String&,“连等a=b=c”
String& operator=(char *s);
String& operator=(const String& s);
//-------------------------------------------------------------------
//重载 + :返回的是String (s=s1+s2;因为如果用String&,会使在执行完+后,s1的值也发生变化)
//friend String operator+(const String& s1,const String& s2);
String operator+(const String& s);
//friend String operator+(const String& s,const char* str);
String operator+(const char* s);
//重载 += :返回的是String
//friend String operator+=(String& s1, const String& s2);
String operator+=(const String& s);
//friend String operator+=(String& s,const char* str);
String operator+=(const char* str);
//-------------------------------------------------------------------
//重载 [] :返回的是char&
char& operator[](int i);
const char& operator[](int i) const;
//重载 << >> :返回的是ostream&
friend ostream& operator<<(ostream &out,String &s);
friend istream& operator>>(istream &in ,String &s);
//-------------------------------------------------------------------
//friend函数:重载> < == !=
friend bool operator<(const String& s1,const String& s2);
friend bool operator>(const String& s1,const String& s2);
friend bool operator==(const String& s1,const String& s2);
friend bool operator!=(const String& s1,const String& s2);