目录
一.什么是运算符重载
运算符重载就是赋予运算符具有操作自定义类型数据的功能。它的本质上就是函数的调用。
运算符重载函数的构成:
函数返回值:由运算后完成的值决定。函数名:operator加上想要重载的运算符。参数:由运算符的操作数以及重载方式决定。
二.运算符重载的方式
1.友元重载
用友元的方式实现运算符重载,其函数参数的个数就是运算符的操作数。我们以实现 “+” 为例子:
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);
其实跟普通函数没啥区别。
2.类成员函数重载
用类成员函数的方式实现运算符重载,参数个数等于运算符操作数-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;
}
这样就可以进行对象的比较了。
三.特殊运算符重载
1.流运算符
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的引用类型时,便可以实现连续输入输出。
2.自增自减运算符重载及文本重载
(1)自增自减
自增自减运算符重载需要解决前置后置的问题,需要增加一个无用参数,以表示当前运算符是后置操作。
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;
}
可以看到,我们实现了自定义类型的自增,自减同理。
(2)文本重载
固定的返回值类型:
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";
}
(3)类的隐式转换
定义一个新的对象,没办法直接把它赋值给一个基本数据类型--->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;
}
四.运算符重载案例
1.手写动态数组
第一步:设计基础元素
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();
}
可以看到,结果跟我们想要的一样!
2.包装一下int
这里比较简单,直接贴代码,代码中已经加好了注释。
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类型
};
3.其他重载
重载():
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();
}
好了,今天的学习就到这啦!