7. C++运算符重载
C++运算符重载
什么是运算符重载
-
运算符重载赋予运算能够操作自定义类型。
-
运算符重载前提条件: 必定存在一个自定义类型
-
运算符重载实质: 就是函数调用
-
友元重载
-
类重载
-
-
在同一自定义类型中,一个运算符只能被重载一次
-
C++重载只能重载已有的运算符,不能重载没有
-
C++重载一般情况不能违背运算符原来的含义(就算语法正确)
-
注意点:
- . ,.* ,?:,:: 不能被重载
#include <iostream>
#include <string>
using namespace std;
class MM
{
public:MM() {}MM(string name, int score) :name(name), score(score) {}
protected:string name;int score;
};
int main()
{int a = 1;int b = 2;int sum = a + b;MM mm("小芳", 6);MM girl("小芳", 2);//error: 没有与这些操作数匹配 "xxx" 运算符//MM result = mm + girl; //错误return 0;
}
重载写法
重载函数的写法
//函数定义方式
函数返回值类型 函数名(参数)
{//函数体;
}
//运算符重载也是函数,只是函数名写法不同
//函数名: operator加上运算符组成函数名
//参数:
// 友元重载: 参数个数等于操作数
// 类成员函数: 参数个数等于操作-1
// 函数返回值类型:运算符组成表达式 最终结果是什么类型就返回类型
// int a; int b; a+b 返回int
// 函数体:写你真正要实现的效果
友元重载
#include <iostream>
#include <string>
using namespace std;
class MM
{
public:MM() {}MM(string name, int score) :name(name), score(score) {}void print() {cout << name << "\t" << score << endl;}//友元重载friend MM operator+(MM a, MM b); //加法重载函数的声明
protected:string name;int score;
};
MM operator+(MM a, MM b)
{return MM(a.name, a.score+b.score); //返回一个匿名对象
}
int main()
{int a = 1;int b = 2;int sum = a + b;MM mm("小芳", 6);MM girl("小芳", 2);//error: 没有与这些操作数匹配 "xxx" 运算符//重载函数的隐式调用 -->mm + girl 解析为:operator+(mm, girl)MM result = mm + girl; //显示绿色就是运算符重载result.print();//重载函数显示调用:按照函数的调用方式MM res = operator+(mm, girl); //operator+:函数名 参数//string aa("12");//string bb("2323");//cout << (aa > bb) << endl;return 0;
}
类重载
#include <iostream>
#include <string>
using namespace std;
class MM
{
public:MM() {}MM(string name, int score) :name(name), score(score) {}void print() {cout << name << "\t" << score << endl;}//友元重载friend MM operator+(MM a, MM b); //加法重载函数的声明
protected:string name;int score;
};
//类成员函数少一个参数: 对象本身可以表示参数
MM MM::operator-(MM object)
{return MM(this->name, this->score - object.score);
}int main()
{MM mul = mm.operator-(girl); //类重载显示调用,跟调用普通成员函数一样的mul.print();MM girlFriend = mm - girl; //编译器mm - girl翻译为: mm.operator-(girl)girlFriend.print();return 0;
}
特殊运算符重载
- 通常情况:单目运算符用类成员函数重载,双目用友元重载
- = ,(),->,[] 只能采用成员函数重载
- ++ --运算符重载
- 增加一个无用参数,标识是后置++或者–
- 流运算符重载(>> <<)
- 输入流对象(cin): istream类
- 输出流对象(cout): ostream类
- 流重载必须用引用
- 流重载一定要用友元重载
- 后缀重载
#include <iostream>
#include <string>
#include <thread>
using namespace std;
class MM
{
public:MM() {}MM(string name, int age) :name(name), age(age) {}void print() {cout << name << "\t" << age << endl;}//MM operator=(MM) = delete; //删掉默认的//函数重载void operator=(int data) {this->age += data;}//++ 为例MM operator++() //前置{this->age++;return *this; //返回对象本身}MM operator++(int) //后置的{return MM(this->name, this->age++);}//流运算符的重载friend ostream& operator<<(ostream& out, MM& object);friend istream& operator>>(istream& in, MM& object);private:string name;int age;
};
ostream& operator<<(ostream& out, MM& object)
{//out当做cout用out << object.name << "\t" << object.age << endl;return out;
}
istream& operator>>(istream& in, MM& object)
{cout << "输入对象属性:";//in当做cin用即可in >> object.name >> object.age;return in;
}
//文本重载, 一般写成下划线系列
//后缀的重载
unsigned long long operator""_h(unsigned long long data)
{return data * 60 * 60;
}
unsigned long long operator""_m(unsigned long long data)
{return data * 60;
}
unsigned long long operator""_s(unsigned long long data)
{return data;
}
int main()
{MM mm("小芳", 18);MM girl;girl = mm; //每一个类中都存在默认的赋值重载girl = 8;girl.print();MM result = ++girl;result.print();girl.print();result = girl++;result.print();girl.print();cin >> girl;cout << girl << endl; //this_thread::sleep_for(10s);cout << 1_h << endl;cout << (1_h + 30_m + 49_s) << endl;return 0;
}
对象的隐式转换
对象隐式转换: 就是让对象能够赋值给普通数据
//operator 转换的类型()
//{
// return 要转换类型的数据;
//}
#include <string>
#include <iostream>
using namespace std;
class MM
{
public:MM() {}MM(string name, int age) :name(name), age(age) {}operator int() {return this->age;}
protected:string name;int age;
};
int main()
{MM mm("mm", 39);int age = mm;cout << age << endl;return 0;
}
()运算符的重载
仿函数
让类型可以模仿函数调用的行为: 函数名(参数); 类名() 调用的函数行为
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;class Data
{
public://operator()组成函数名void operator()() {cout << "无参重载()" << endl;}void operator()(int a, int b) {cout << "有参重载(a,b)" << endl;}
protected:};
int main()
{//greater<int>(); //比较准则//int array[5] = { 3,4,1,2,32 };//sort(array, array + 5, greater<int>());//for (auto& v : array) //{// cout << v << "\t";//}//cout << endl;Data data;data.operator()(); //显式调用data.operator()(1, 2); //显式调用data(); //隐式调用data(1, 2); //隐式调用Data{}(); //{}帮助识别 Data()Data{}(2, 3);return 0;
}
运算符重载案例分析
智能指针
智能指针是用对象方式管理new的内存,可以做到自动释放(本质是析构函数自动调用)内存的功能
#include <iostream>
#include <memory>
using namespace std;
class Auto_Ptr
{
public:Auto_Ptr(int* ptr) :ptr(ptr) {}~Auto_Ptr() {if (ptr) {delete ptr;ptr = nullptr;}}//访问指针int* operator->() {return this->ptr;}//访问数据int& operator*() {return *ptr;}//禁止拷贝,禁止赋值Auto_Ptr(Auto_Ptr&) = delete;Auto_Ptr& operator=(Auto_Ptr&) = delete;
protected:int* ptr;
};
int main()
{Auto_Ptr object(new int(1999));cout << *object << endl;//shared_ptr<int> p(new int(19999));//cout << *p << endl;//shared_ptr<double> p2(new double(19.99));//cout << *p2 << endl;return 0;
}
封装数组
#include <iostream>
#include <vector> //动态数组
using namespace std;
class my_vector
{
public:my_vector(int capacity = 10) :capacity(capacity) {mem = new int[capacity] {0};curSize = 0;}void push_back(int data) {mem[curSize++] = data;}int* begin() {return mem + 0;}int* end() {return mem + capacity;}int& operator[](int index) {if (curSize < index)curSize = index;return mem[index];}//万金油函数int size() {return curSize;}int empty() {return curSize == 0;}~my_vector() {if (mem) {delete[] mem;mem = nullptr;}}
protected:int* mem;int capacity;int curSize;
};int main()
{my_vector vec;for (int i = 0; i < 3; i++) {vec[i] = i;}for (auto v : vec) {cout << v << "\t";}cout << endl;cout << vec.size() << endl;for (int i = 0; i < vec.size(); i++) {cout << vec[i] << "\t";}cout << endl;return 0;
}
迭代器实现
//迭代器就是让一个类中类去遍历数据
#include <iostream>
#include <string>
using namespace std;
struct Node
{int data;Node* next;Node() :next(nullptr){}Node(int data) :data(data), next(nullptr) {}Node(int data, Node* next) :data(data), next(next) {}
};
class List
{
public:List() :headNode(new Node),curSize(0){}void push_front(int data) {headNode->next = new Node(data, headNode->next);curSize++;}Node* begin() {return headNode->next;}Node* end() {return nullptr;}class iterator {public:iterator() :pmove(nullptr) {}void operator=(Node* pmove) {this->pmove = pmove;}bool operator!=(Node* pmove) {return this->pmove != pmove;}iterator operator++() {this->pmove = this->pmove->next; //链表++不了return *this;}int operator*() {return this->pmove->data; //*运算访问数据}private:Node* pmove; //需要指针访问数据};protected:Node* headNode;int curSize;
};
void my_list()
{List list;for (int i = 0; i < 3; i++) {list.push_front(i);}List::iterator it;for (it = list.begin(); it != list.end(); ++it){cout << *it << " ";}cout << endl;
}
int main()
{string str = "ILoveyou";for (int i = 0; i < str.size(); i++) {cout << str[i];}cout << endl;//类中类访问一个容器数据string::iterator it;for (it = str.begin(); it != str.end(); it++) {cout << *it; //*指针取值运算}cout << endl;//cout << *str.end() << endl;my_list();return 0;
}
重载的特殊问题
//对象与常量运算
#include <iostream>
#include <string>
using namespace std;
class Data
{
public:Data() {}Data(int num) :num(num) {}//friend Data operator+(Data data, int num);//friend Data operator+( int num, Data data);//Data operator+(Data data) //{// return Data(this->num + data.num);//}void print() {cout << num << endl;}friend Data operator+(Data data1, Data data2);
protected:int num;
};
//Data operator+(Data data, int num)
//{
// return Data(data.num + num);
//}
//Data operator+(int num, Data data)
//{
// return Data(num + data.num);
//}
Data operator+(Data data1, Data data2)
{return Data(data1.num + data2.num);
}
int main()
{Data data(1);Data temp;//data.成员函数(1);temp = data + 1;//1+data : 1.成员函数()temp = 1 + data; //类成员函数没办法完成temp.print();return 0;
}