1.不能重载的: . :: .* ?: sizeof
2.操作符重载是通过函数实现的。
class Complex
{
public:
int a,b;
public:
Complex(int a=0,int b=0)
{
this->a =a;
this->b =b;
}
void printCom()
{
std::cout<<this->a<<" + "<<this->b<<"i\n";
}
};
Complex complexAdd(Complex &c1,Complex &c2)
{
Complex tmp;
tmp.a = c1.a + c2.a;
tmp.b = c1.b + c2.b;
return tmp;
}
Complex operator+(Complex &c1,Complex &c2)
{
Complex tmp;
tmp.a = c1.a + c2.a;
tmp.b = c1.b + c2.b;
return tmp;
}
void main()
{
Complex c1(1,2),c2(3,4);
//如果没有重载+操作符,c1+c2是会出错的。
//int是基础数据类型,C++编译器已经为这些类型提供了+号操作
//自定义数据类型需要自己重载运算符操作。
//1.我们通过全局函数,实现两个复数的相加,但是还要写函数名,太麻烦了,不直观。
//Complex c3 = complexAdd(c1,c2);
//2.我们将全局函数名改为operator+
//这样我们就可以像下面这样调用operator+函数,和普通的函数调用方法是一致的。
//Complex c3 = operator+(c1,c2);
//3.现在我们直接写c1+c2竟然没报错,也能运行,说明,操作符重载本质上就是函数调用。
//c2 = c1 + c2;//重载 + 号运算符
system("pause");
}
操作符重载的两种方法:
1.友元函数实现操作符重载
注意到没有,我们的Complex类中的a,b成员变量是public的,这样全局重载函数在外部才能访问类的公有成员,但是一般情况下,我们将类的成员变量设置为私有的。那么就不能再使用全局重载函数了,有两种解决方案,一种是友元函数实现,一种是成员函数实现 。我们先看友元函数实现,其实很简单。我们只要将前面的全局重载函数声明为Complex类的友元函数即可,这样友元函数在外部就可以访问类的私有成员变量。
class Complex
{
/*public*/
private:
int a,b;
//通过友元函数实现 + 号重载
friend Complex operator+(Complex &c1,Complex &c2);
public:
Complex(int a=0,int b=0)
{
this->a =a;
this->b =b;
}
void printCom()
{
std::cout<<this->a<<" + "<<this->b<<"i\n";
}
}
Complex operator+(Complex &c1,Complex &c2)
{
Complex tmp;
tmp.a = c1.a + c2.a;
tmp.b = c1.b + c2.b;
return tmp;
}
2.成员函数实现操作符重载
另一种实现访问私有变量的方法就是通过使用成员函数。
注意:左操作数被隐藏在this指针中。
class Complex
{
/*public*/
private:
int a,b;
public:
Complex(int a=0,int b=0)
{
this->a =a;
this->b =b;
}
void printCom()
{
std::cout<<this->a<<" + "<<this->b<<"i\n";
}
//通过类的成员函数,实现 - 号重载。
//注意:隐藏了this指针
Complex operator-(Complex &c2)
{
Complex tmp;
tmp.a = this->a - c2.a ;
tmp.b = this->b - c2.b ;
return tmp;
//这里返回Complex&好不好???
//不好。因为 tmp是临时对象,当函数指向完毕之后,会被析构,而返回的是一个匿名对象,该匿名对象是由拷贝构造函数创建的。
//因为tmp 被析构会清空其内存,如果其中有指针成员的话,指针指向的内存也会被释放,如果匿名对象是由浅拷贝创建的话,则匿名对象中的指针是野指针。
//如果返回c2对象的话,则可以返回引用。为啥?
//因为c2已经存在,作为形参,只是一个引用,它的生命周期与当前函数无关,返回引用也是没有问题的。
}
}
void main()
{
Complex c1(1,2),c2(3,4);
//通过成员函数 实现 重载 - 号 操作符
//Complex c4 = c1.operator-(c2);
//上面的调用方法和下面是等价的。因为是成员函数,所以可以使用类的对象点出方法来。
Complex c4 = c1 - c2;
}
接下来,看看单操作数的操作符重载。
1.前置++(–)重载
class Complex
{
/*public*/
private:
int a,b;
//前置 ++
friend Complex& operator++(Complex &c2);
public:
Complex(int a=0,int b=0)
{
this->a =a;
this->b =b;
}
void printCom()
{
std::cout<<this->a<<" + "<<this->b<<"i\n";
}
//使用成员函数实现 前置 --
Complex& operator--()
{
this->a --;
this->b--;
return *this;
}
};
//全局函数实现前置++,在类中声明为类的友元函数
//这里一般返回值为类的引用而不是一个匿名对象
Complex& operator++(Complex &c2)
{
c2.a ++;
c2.b ++;
return c2;
}
void main()
{
Complex c1(1,2),c2(3,4);
//全局函数实现
++c1;
c1.printCom();
//类成员函数实现
--c2;
c2.printCom();
system("pause");
}
2.后置++(–)重载
因为后置++的重载函数和前置++的重载函数参数和名称都一样,C++为了以示区别,在后置++的重载函数的参数中多加了一个int参数,just为了区别前置++,没有任何意义。
class Complex
{
/*public*/
private:
int a,b;
//全局函数实现后置 ++
//后置++ ,先使用c2的属性,再让c2 的属性++
friend Complex operator++(Complex &c2,int);//int只是一个占位参数,为了和前置++区分
public:
Complex(int a=0,int b=0)
{
this->a =a;
this->b =b;
}
void printCom()
{
std::cout<<this->a<<" + "<<this->b<<"i\n";
}
//成员函数实现后置 --
Complex operator--(int)
{
Complex tmp = *this;
this->a --;
this->b --;
return tmp;
}
};
//全局函数实现后置++
// 为啥返回返回一个对象,而不是一个引用?
// 因为,Complex tmp是一个局部对象,该函数调用结束之后tmp对象会被回收,C++通过在内存中创建一个匿名对象,将tmp的内存拷贝给匿名对象返回,所以,这里返回一个匿名对象比较合适。
Complex operator++(Complex &c2,int)
{
//先使用c2的属性,再让c2 的属性++
Complex tmp ;
tmp = c2;
c2.a ++;
c2.b ++;
return tmp;
}
void main()
{
Complex c1(1,2),c2(3,4);
//全局函数实现后置++
c1++;
c1.printCom();
//类成员函数实现后置--
c2--;
c2.printCom();
system("pause");
}
友元函数重载和成员函数重载的区别?
什么时候该用友元函数重载,什么时候该用成员函数重载呢?我们先看下面的例子。
#include <iostream>
class Complex
{
private:
int a,b;
//重载 << 运算符
friend void operator<< (std::ostream &out , Complex &c2);
public:
Complex(int a=0,int b=0)
{
this->a =a;
this->b =b;
}
void printCom()
{
std::cout<<this->a<<" + "<<this->b<<"i\n";
}
};
//使用全局函数实现<<重载
//可以使用类成员函数实现<<重载吗?
//不能,因为ostream类的源代码我们不能修改,所以只能使用全局函数结合友元函数实现<<重载
//这是友元函数存在的最大的意义,一般情况下友元函数都用在于此,其他情况都不建议使用友元函数。
void operator<<(std::ostream &out , Complex &c2)
{
std::cout<<c2.a<<" + "<<c2.b<<"i\n";
}
void main()
{
Complex c1(1,2),c2(3,4);
//如果我们希望使用cout<<c1输出c1则需要重载<<操作符。
//重载 << 运算符
//1.使用友元函数
//std::cout<<c1;
//2.能不能使用成员函数
// cout.operator<<(std::ostream &out , Complex &c2)
// cout.operator<<(Complex &c2)
// 这样就需要在cout类的成员函数中加一个上述的函数,这是不可能的。
// 所以向这种操作符重载只能使用友元函数重载。
system("pause");
}
如何实现链式编程
#include <iostream>
class Complex
{
private:
int a,b;
//重载 << 运算符
//如何实现 << 链式编程 --> 返回对象的引用
friend std::ostream& operator<<(std::ostream &out , Complex &c2);
public:
Complex(int a=0,int b=0)
{
this->a =a;
this->b =b;
}
void printCom()
{
std::cout<<this->a<<" + "<<this->b<<"i\n";
}
};
std::ostream& operator<<(std::ostream &out , Complex &c2)
{
std::cout<<c2.a<<" + "<<c2.b<<"i\n";
return out;
}
void main()
{
Complex c1(1,2),c2(3,4);
//重载 << 运算符
//返回值作为左值,必须返回对象引用
std::cout<<c1<<std::endl<<"链式编程"<<std::endl;
//operator<<(std::cout,c1);
//等价于 cout<<c1;
system("pause");
}