C++学习笔记(6)

目录

一.什么是运算符重载

二.运算符重载的方式

1.友元重载

2.类成员函数重载

三.特殊运算符重载

1.流运算符

2.自增自减运算符重载及文本重载

(1)自增自减

(2)文本重载

(3)类的隐式转换  

 四.运算符重载案例

1.手写动态数组

2.包装一下int

3.其他重载


一.什么是运算符重载

运算符重载就是赋予运算符具有操作自定义类型数据的功能。它的本质上就是函数的调用

运算符重载函数的构成:

函数返回值:由运算后完成的值决定。函数名: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++学习笔记(6)

注意,我们看到的 “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;
}

C++学习笔记(6)

 如图,当我们把返回值修改成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;
}

C++学习笔记(6)

 可以看到,我们实现了自定义类型的自增,自减同理。

(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";
}

C++学习笔记(6)

(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();
}

C++学习笔记(6)

 可以看到,结果跟我们想要的一样!

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();
}

好了,今天的学习就到这啦!

上一篇:2022.02.09-高宝琪毕设阶段性汇报


下一篇:C++基础知识 - 函数模板的概念