目录
一.什么是运算符重载
二.运算符重载的方式
1.友元重载
2.类成员函数重载
三.特殊运算符重载
1.流运算符
2.自增自减运算符重载及文本重载
(1)自增自减
(2)文本重载
(3)类的隐式转换
四.运算符重载案例
1.手写动态数组
2.包装一下int
3.其他重载
运算符重载就是赋予运算符具有操作自定义类型数据的功能。它的本质上就是函数的调用。
运算符重载函数的构成:
函数返回值:由运算后完成的值决定。函数名:operator加上想要重载的运算符。参数:由运算符的操作数以及重载方式决定。
用友元的方式实现运算符重载,其函数参数的个数就是运算符的操作数。我们以实现 “+” 为例子:
class Complex { public: Complex(int a,int b):a(a),b(b){} void print() { cout << a << " " << b << endl; } friend Complex operator+(Complex one, Complex two) { return Complex(one.a + two.a, one.b + two.b); } protected: int a; int b; }; int main() { Complex a(1, 1); Complex b(2, 0); Complex c = a + b; c.print(); }
注意,我们看到的 “c = a + b” 是运算符重载的隐式调用,显式调用如下:
Complex c = operator+(a, b);
其实跟普通函数没啥区别。
用类成员函数的方式实现运算符重载,参数个数等于运算符操作数-1,因为类成员函数本质上是类里的东西,需要用对象来调用,所以参数自然少了一个。我们以实现 “>” 为例子:
bool operator>(Complex object) { if (this->a > object.a) return true; else if (this->a == object.a && this->b > object.b) return true; else return false; }
这样就可以进行对象的比较了。
cin类型:istream类的对象。
cout类型:ostream类的对象。
流运算符:“<<” ,“>>”。
friend void operator>>(istream& in, A& a) { in >> a.name >> a.age; } friend void operator<<(ostream& out, A& a) { out << a.name << '\t' << a.age << endl; }
按照上面的写法我们可以实现输入和输出我们定义的类A,但这种实现是有局限的,因为返回的是void类型,所以不能做连续输入和输出,那这个要怎么优化呢?
class A { public: A(string name = "", int age = 10) :name(name), age(age) {} friend istream& operator>>(istream& in, A& a) { in >> a.name >> a.age; cout << endl; return in; } friend ostream& operator<<(ostream& out, A& a) { out << a.name << '\t' << a.age << endl; return out; } protected: string name; int age; }; int main() { A a("小蓝", 18); A b("小绿", 19); A c; A d; cin >> c >> d; cout << a << b << c << d; }
如图,当我们把返回值修改成istream和ostream的引用类型时,便可以实现连续输入输出。
自增自减运算符重载需要解决前置后置的问题,需要增加一个无用参数,以表示当前运算符是后置操作。
A operator++(int) { return A(name, age++); } A operator++() { return A(name, ++age); }
我们来编写一些测试案例:
class A { public: A(string name = "", int age = 10) :name(name), age(age) {} friend ostream& operator<<(ostream& out, A& a) { out << a.name << '\t' << a.age << endl; return out; } A operator++(int) { return A(name, age++); } A operator++() { return A(name, ++age); } protected: string name; int age; }; int main() { A a("小蓝", 18); A object = a++; cout << object << a; object = ++a; cout << object << a; }
可以看到,我们实现了自定义类型的自增,自减同理。
固定的返回值类型:
unsigned long long
固定的函数名:
operator""
固定参数类型:
unsigned long long
一般要进行多次单位转换的时候,可以使用文本重载,下面给出一个换算时间的例子:
unsigned long long operator"" _h(unsigned long long num) { return num * 60 * 60; } unsigned long long operator"" _min(unsigned long long num) { return num * 60; } unsigned long long operator"" _s(unsigned long long num) { return num; } int main() { int second = 1_h + 10_min + 20_s; cout << second << "s"; }
定义一个新的对象,没办法直接把它赋值给一个基本数据类型--->1.重载运算符 2.隐式转换
class A { public: A(string name ,int age):name(name),age(age){} //类的对象的隐式转换 operator int() { return age; } protected: string name; int age; }; int main() { A a("a", 18); int age= a; cout << age<< endl; return 0; }
第一步:设计基础元素
class vector { public: protected: int size; //当前元素个数 int* base; //存储空间 int capacity; //容量 };
第二步:写构造函数和析构函数
vector(int capacity) :capacity(capacity) { if (capacity > 0) { base = new int[capacity]; this->capacity = capacity; this->size = 0; } } ~vector() { if (base) { delete[] base; base = nullptr; } }
第三步:写两个万金油函数
bool empty() const { return size == 0; } int getsize()const { return size; }
第四步:实现下标访问
int& operator[](int index) { if (index >= 0 && index < capacity) { return base[index]; } }
第五步:接着实现动态数组增长
void push_back(int data) { if (size == capacity) { int* newbase = new int[capacity * 2]; this->capacity *= capacity; for (int i = 0; i < size; i++) { newbase[i] = base[i]; } delete[] base; base = newbase; } base[size++] = data; }
最后,写一些调试代码试试看!
int main() { vector a(3); for (int i = 0; i < 5; i++) { a.push_back(i); cout << a[i] << " "; } cout << endl << a.getsize(); }
可以看到,结果跟我们想要的一样!
这里比较简单,直接贴代码,代码中已经加好了注释。
class Int { public: Int(int num) :num(num) {} int& data() { return num; //获取数据 } string tostr() { return to_string(num); //把int转换为string类型 } //算术运算符重载 Int operator+(const Int& value) //+ 对象相加 类中成员函数重载的方式 { return Int(this->num + value.num); } //友元重载: 操作数==重载函数的参数个数 friend Int operator-(const Int& one, const Int& two) { return Int(one.num - two.num); } Int operator+=(const int& value) //原来的值+=int类型的值 { return Int(this->num + value); } Int operator+=(const Int& value) //原来的值+=一个对象 形成重载|参数类型不一致 { return Int(this->num + value.num); } Int operator++(int) { return Int(this->num++); } Int operator++() { return Int(++this->num); } //位运算符重载 Int operator&(const Int& value) { return Int(this->num & value.num); } bool operator!() { return !this->num; } //负号 Int operator-() { return Int(-this->num); } //流重载 friend ostream& operator<<(ostream& out, const Int& object) { out << object.num << endl; return out; } friend istream& operator>>(istream& in, Int& object) { in >> object.num; return in; } //取地址符重载 int* operator&() { return &this->num; //不需要返回对象,返回int*类型的地址即可 } //关系运算符重载 bool operator>(const Int& object) { return this->num > object.num; } protected: int num; //数据还是int类型 };
重载():
class Function { typedef void(*PF)(); public: Function(PF pf) :pf(pf){} void operator()() { pf(); } protected: PF pf; }; void print() { cout << "重载成功"; } int main() { Function f(print); f(); }
重载->:
class A { public: A(string name,int age):name(name),age(age){} void print() { cout << name << " " << age << endl; } protected: string name; int age; }; class Auto_ptr { public: Auto_ptr(int* ptr):ptr(ptr){} Auto_ptr(A* pa):pa(pa){} int& operator*() { return *ptr; } A* operator->() { return pa; } ~Auto_ptr() { if (ptr) { delete ptr; ptr = nullptr; } if (pa) { delete pa; pa = nullptr; } } protected: int* ptr; A* pa; }; int main() { Auto_ptr ptr(new int(18)); cout << *ptr << endl; Auto_ptr ptra(new A("小蓝", 20)); ptra->print(); }
好了,今天的学习就到这啦!