4.5运算符重载
1. 加号运算符重载
2. 左移运算符重载
cout:标准输出流对象,这个对象全局只能有一个,所以只能用引用的方式传递
一直往后面追加输入:链式编程的思想:
链式编程思想:是将多个操作(多行代码)通过点号(.)链接在一起成为一句代码,使代码可读性好。a(1).b(2).c(3)
链式编程特点:方法的返回值是block,block必须有返回值(本身对象),block参数(需要操作的值)
代表:Masonry框架。
还可以把重载函数里面的cout改为out(引用是起别名)
把m_a和m_b改成私有后 需要把重载函数设置为友元
3. 递增运算符重载(如何区分前置后置、后置递增有问题)
想要实现的功能:
可以对类的对象中的整形数据进行前置递增或者后置递增操作最后输出这个数据(后置递增实现难一些)
步骤:
重载左移运算符
重载递增运算符:先进行++运算再将自身做返回(返回引用);
如果不返回引用而返回值就不能嵌套:每次返回的是一个新的变量,这个变量的值=返回值;
难点:
用占位参数int来区分前置和后置递增
后置递增的实现;先记录当前值、进行递增操作、返回记录值;
复习:
1.返回值不同不能作为函数重载的条件
函数重载的四个条件:函数名相同,形参数量不同,形参类型不一样,形参顺序不一样
2.占位参数:占位参数只有参数类型声明,而没有参数名声明
问题:(没有看懂)
解决方法:将左移重载函数的第二个参数加了const。
原因:
因为在cout<<myint++的时候相当于调用“ostream& operator<<(ostream &cout, const MyIntger& myint)”函数,而myint++作为它第二个参数传入,myint++也相当于调用了“MyIntger operator++(int)”结果是一个值类型的返回,而这个值本身是只读的。所以在调用operator<<函数时,形参得加const。
#include<iostream>
using namespace std;
class Myinteger
{
public:
Myinteger()
{
m_a = 0;
}
friend ostream & operator<< (ostream& cout, Myinteger& myint);
//重载递增运算符用成员函数来完成
Myinteger& operator++()
{
m_a++;
return *this;
}
//重载后置递增运算符
//void operator++(int) int代表占位操作,可用于区分前置递增和后置递增。
//函数重载条件:函数名相同,形参数量不同、形参的类型不同、形参的顺序不同
//显然前置递增和后置递增不属于简单的函数重载
Myinteger operator ++(int)
{
Myinteger temp = *this;
m_a++;
return temp;
}
private:
int m_a;
};
// 重载左移运算符
ostream & operator<< (ostream & cout, Myinteger & myint)
{
cout << myint.m_a;
return cout;
}
void test01()
{
Myinteger myint;
cout << ++myint <<endl;
cout << myint;
}
void tesr02()
{
Myinteger myint;
cout << myint++ << endl;;
cout << myint;
}
int main()
{
test01();
system("pause");
return 0;
}
4.赋值运算符重载
复习:
c++编译器至少给一个类添加4个函数
默认构造函数(无参,函数体为空)
默认析构函数(无参,函数体为空)
默认拷贝构造函数,对属性进行值拷贝
赋值运算符 operator=, 对属性进行值拷贝
目的:
如果类中有属性指向堆区,会出现深浅拷贝问题(堆区数据重复释放)
解决问题:
如何重载
什么时候重载
#include<iostream>
using namespace std;
class person
{
public:
person(int age) //传进来一个数据 构造函数
{
m_age = new int(age);//在堆区开辟内存存放这个数据 并且让指针维护这个堆区的数据
} //堆区开辟的数据会返回一个相应的类型指针 这里返回一个int *类型数据(m_age也是这个类型)
int* m_age;
person& operator=(person& p) //重载函数 注意:此处要以引用或者指针的形式传入
{
//1.注意:这里的重载函数的参数一定要以引用或者指针的形式传入!!
//2.不然在传入的时候进行了一次拷贝将赋值右边p2的值传入的时候临时变量记录的p2的属性m_Age的地址
//3.而出了赋值运算符重载函数会进行一次析构 这时p2的属性new出来的空间已经被释放了
//不用引用会报错,不用引用的话又调用浅拷贝了,又重复释放了
if (m_age != NULL) //当我们要实现p1=p2时,首先要先把p1自己的值删除干净,再接受p2的值;
{
delete m_age; //把这个地址内存释放干净
m_age = NULL;// 让这个变量为空
}
m_age = new int(*p.m_age);
return *this;
}
~person() //析构函数
{
if (m_age != NULL)
{
delete m_age;
m_age = NULL;
}
}
};
void test01()
{
person p1(18);
person p2(28);
person p3(20);
p1 = p2=p3;
cout << "p1的年龄:" <<*p1.m_age << endl;
cout << "p2的年龄:" << *p2.m_age << endl;
cout << "p3的年龄:" << *p3.m_age << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
5.关系运算符重载
自定义数据类型,编译器不知道如何对比。
“==”
“!=”
#include<iostream>
using namespace std;
class person
{
public:
person(string name,int age)
{
m_name = name;
m_age = age;
}
bool operator==(person& p)
{
if (this->m_name == p.m_name && this->m_age == p.m_age)
{
return true;
}
else return false;
}
bool operator!=(person& p)
{
if (this->m_name != p.m_name||this->m_age == p.m_age)
{
return true;
}
else return false;
}
string m_name;
int m_age;
};
void test01()
{
person p1("zhang" ,15);
person p2("liu", 17);
if (p1==p2)
{
cout << "p1和p2相等" << endl;
}
else { cout << "p1和p2不相等" << endl; }
if (p1 != p2)
{
cout << "p1和p2不相等" << endl;
}
else { cout << "p1和p2相等" << endl; }
}
int main()
{
test01();
system("pause");
return 0;
}
6.函数调用运算符重载
- 函数调用运算符 () 也可以重载
- 由于重载后使用的方式非常像函数的调用,因此称为仿函数
- 仿函数没有固定写法,非常灵活
- 看到: 类型+() 就要想到匿名函数对象
#include<iostream>
using namespace std;
class print //重载1
{
public:
void operator()(string text)
{
cout << text << endl;
}
};
void test01()
{
print p1;
p1("hello world");
}
class add //重载2
{
public:
int operator()(int a, int b)
{
return a + b;
}
};
void test02()
{
add p2;
cout << p2(4, 9) << endl;
// 匿名对象调用
cout << "add()(100,100) = " << add()(100, 100) << endl;
}
int main()
{
test01();
test02();
system("pause");
return 0;
}