c++学习——函数重载、运算符重载

重载

    • 函数重载的基本概念
    • 函数重载的原理
    • c++调用c语言函数
    • **运算符重载的概念**
    • **加号运算符重载**
    • **减号运算符重载**
    • **左移运算符重载**
    • **右移运算符重载**
    • **赋值运算符重载**
    • **关系运算符重载**
    • **前置加加和后置加加**
    • **数组下标重载**
    • **函数调用运算符重载**

函数重载的基本概念

函数重载的目的:是为了更好地去使用函数名
函数重载的条件:同一个作用域,参数的个数不同,参数的顺序不同,参数的类型不同
c语言中不允许出现相同地函数名,而在c++中是允许出现相同的函数名的

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

//参数的个数不同
void func()
{
	cout << "func()" << endl;
}

void func(int a)
{
	cout << "func(int a)" << endl;
}

//参数的类型不同
void func(char c)
{
	cout << "func(char c)" << endl;
}

//参数的顺序不同
void func(int a, double b)
{
	cout << "func(int a, double b)" << endl;
}

void func(double b, int a)
{
	cout << "func(double b, int a)" << endl;
}

void test01()
{
	int a = 10;
	double b = 3.14;
	func();
	//func(b);//err double转换不了成为int或char
	func(a, b);
	func(b, a);
	char c = 'c';
	func(c);// char可以转换int,调用int参数的函数
}

int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

函数重载和函数的默认参数一起使用,需要注意二义性问题
编译器是通过你调用函数时,传入的参数来判断调用重载的哪个函数,我们调用函数时不需要写返回值,所以返回值不能成为函数重载的条件

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

//参数的个数不同
void func()
{
	cout << "func()" << endl;
}

void func(int a)
{
	cout << "func(int a)" << endl;
}

//参数的类型不同
void func(char c)
{
	cout << "func(char c)" << endl;
}

//参数的顺序不同
void func(int a, double b)
{
	cout << "func(int a, double b)" << endl;
}

void func(double b, int a)
{
	cout << "func(double b, int a)" << endl;
}

void test01()
{
	int a = 10;
	double b = 3.14;
	//编译器是通过你调用的函数时,传入的参数来判断调用重载的哪个函数
	func();
	//func(b);//err double转换不了成为int或char
	func(a, b);
	func(b, a);
	char c = 'c';
	func(c);// char可以转换int,调用int参数的函数
}

//--------------------------------------------------------

//函数重载和函数的默认参数一起使用
void myfunc(int a, int b = 0)
{
	cout << "myfunc(int a, int b = 0)" << endl;
}

void myfunc(int a)
{
	cout << "myfunc(int a)" << endl;
}

void test02()
{
	//myfunc(10);//err  二义性  不知道调用哪个函数
}

int main()
{
	test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

函数重载的原理

函数重载的原理是在汇编时,给各个函数取别名,C语言不能重载的原因是没有取别名
C++的函数在汇编时,会给函数取别名,C语言的不会,这时,如果C++来调用C语言的函数,C++会去找取了别名的函数,但是C语言没有取别名,这时会出错

c++调用c语言函数

在这里插入图片描述
test.h

#pragma once

#include

//告诉c++编译器,找下面的函数要以c语言方式去寻找
#ifdef __cplusplus
extern "C"
{
#endif
	void func();

#ifdef __cplusplus
}
#endif

test.c

#include "test.h"


void func()
{
	printf("func\n");
}

22 c++调用c语言函数.cpp

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;
#include"test.h"

int main()
{
	func();
	system("pause");
	return EXIT_SUCCESS;
}

运算符重载的概念

1.运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
2.运算符重载的目的是让语法更加简洁
3.运算符重载不能改变本来寓意,不能改变基础类型寓意
4.运算符重载的本质是另一种函数调用(是编译器去调用)
5.这个函数同一的名字叫operator
6.重载函数可以写成全局或成员函数
7.重载函数如果写成全局的,那么双目运算符左边的是第一个参数,右边是第二个参数
8.重载函数如果写成成员函数,那么双目运算符的左边是this,右边是第一个参数
9.不能改变运算符优先级,不能改变运算符的参数个数

c++学习——函数重载、运算符重载_第1张图片
短路规则是:与运算前面假就假后面无需判断,或者是或运算前面真就真后面无需判断
c++学习——函数重载、运算符重载_第2张图片

加号运算符重载

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class Maker
{
public:
	Maker(int id, int age)
	{
		this->id = id;
		this->age = age;
	}
	//写成成员函数,那么只需要一个参数,这个参数是加号的右边
	Maker operator+(Maker &m2)
	{
		Maker temp(this->id + m2.id, this->age + m2.age);
		return temp;
	}
public:
	int id;
	int age;
};

//全局方式  //2、编译器调用这个函数
//Maker operator+(Maker &p1,Maker &p2)//3、编译器检查参数是否对应
//{
//	Maker temp(p1.id + p2.id, p1.age + p2.age);
//	return temp;
//}

void test01()
{
	Maker m1(1, 20);
	Maker m2(2, 22);

	Maker m3 = m1 + m2;//1、编译器看到两个对象相加,那么编译器会去找有没有叫operator+的函数
	cout << "id:" << m3.id << "age:" << m3.age << endl;
	//复数加
	Maker m4 = m1 + m2 + m3;//先是m2+m3
	cout << "id:" << m4.id << "age:" << m4.age << endl;
}

//不同类型的加法运算符重载
class Student
{
public:
	Student()
	{
		mid = 0;
	}
	Student(int id)
	{
		mid = id;
	}
public:
	int mid;
};

//返回值是任意一个类都行
Maker operator+(Maker &m,Student &s)
{
	Maker tmp(m.id + s.mid, 20);//20随便传的一个参数
	return tmp;
}

Maker operator+(Student &s,Maker &m)
{
	Maker tmp(s.mid + m.id,20);//20随便传的一个参数
	return tmp;
}

void test()
{
	Maker m1(1, 18);
	Student s1(2);
	Maker m2 = m1 + s1;
	Maker m3 = s1 + m1;
}

int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

减号运算符重载

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class Maker
{
public:
	Maker(int id)
	{
		this->id = id;
	}
public:
	int id;

	//写成成员函数,那么只需要一个参数,这个参数是减号的右边
	Maker operator-(Maker &m2)
	{
		Maker tmp(this->id - m2.id);
		return tmp;
	}
};

int operator-(Maker &m, int b)
{
	return m.id - b;
}

void test()
{
	Maker m1(10);
	Maker m2(5);
	Maker m3 = m1 - m2;
	cout << m3.id << endl;

	int a = m3 - 5;
	cout << a << endl;
}

int main()
{
	test();
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

左移运算符重载

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;
#include 

class Maker
{
	friend ostream& operator<<(ostream &out, Maker &m);
public:
	Maker(int id,string name)
	{
		this->id = id;
		this->name = name;
	}
private:
	int id;
	string name;
};

//1、形参和实参是一个对象
//2、不能改变库类中的代码
//3、ostream中把拷贝构造函数私有化了
//4、如果要和endl一起使用必须返回ostream的对象

//cout其实是个类
//void operator<<(ostream &out,Maker &m)
ostream& operator<<(ostream &out,Maker &m)
{
	cout << m.id << " " << m.name << endl;

	return out;
}

void test01()
{
	Maker m(10,"露琪亚");
	//对应的上面第一个void operator的注释
	//cout << m.id << endl;//现在就是err 因为返回的是void  
	cout << m << endl;
	cout << m;//返回的是void

	cout << endl;//endl是内联函数
	/*endl是一个函数
	operator<<(函数指针)
	operator<<(endl)
	*/
	cout << 10;//内部重载了基础数据类型
	cout << endl;

}

int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

右移运算符重载

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;
#include

void test()
{
	int a;
	cin >> a;
	cout << a << endl;
}

class Maker
{
	friend istream &operator>>(istream &in, Maker &m);
public:
	Maker(string name, int age)
	{
		this->name = name;
		this->age = age;
	}
	int getAge()
	{
		return age;
	}
private:
	string name;
	int age;
};

istream &operator>>(istream &in, Maker &m)
{
	in >> m.age;
	in >> m.name;
	return in;
}

void test02()
{
	Maker m("悟空", 15);
	Maker m2("悟空", 15);
	cin >> m >> m2;

	cout << m.getAge() << endl;
	cout << m2.getAge() << endl;
}

int main()
{
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

c++学习——函数重载、运算符重载_第3张图片

赋值运算符重载

编译器默认给类提供了一个默认的赋值运算符重载函数
默认的赋值运算符重载函数进行了简单的赋值操作
当类有成员指针时,然后在构造函数中申请堆区空间,在析构函数中释放堆区空间

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class Maker
{
public:
	Maker()
	{
		id = 0;
		age = 0;
	}
	Maker(int id, int age)
	{
		this->id = id;
		this->age = age;
	}
public:
	int id;
	int age;
};

void test()
{
	Maker m1(10, 20);
	Maker m2;

	m2 = m1;//赋值操作

	//默认的赋值运算符重载函数进行了简单的赋值操作
	cout << m2.id << " " << m2.age << endl;
}

class Student
{
public:
	Student(const char *name)
	{
		pName = new char[strlen(name) + 1];
		strcpy(pName, name);
	}

	//防止浅拷贝
	Student(const Student &stu)
	{
		pName = new char[strlen(stu.pName) + 1];
		strcpy(pName, stu.pName);
	}

	//重写赋值运算符重载函数
	
	Student &operator=(const Student &stu)
	//如果不返回&的话相当于是Student operator=s1 相当于调用了一次拷贝构造函数
	{
		//1.不能确定this->pName指向的空间是否能装下stu中的数据,所以先释放thist指向的空间
		if (this->pName != NULL)
		{
			delete[] this->pName;
			this->pName = NULL;
		}

		//2、申请堆区空间,大小由stu决定
		this->pName = new char[strlen(stu.pName) + 1];
		//3、拷贝数据
		strcpy(this->pName, stu.pName);
		//4、返回对象本身
		return *this;//*this返回的是对象的本身   s1 s2 s3
	}

	~Student()
	{
		if (pName!=NULL)
		{
			delete[] pName;
			pName = NULL;
		}
	}

	void printStudent()
	{
		cout << "pName:" << pName << endl;
	}
public:
	char *pName;
};

void test02()
{
	Student s1("卡卡罗特");
	Student s2("露琪亚");

	s1.printStudent();
	s2.printStudent();

	s1 = s2;//赋值操作  析构函数会导致同一块空间被释放两次
	//还会导致内存泄露

	s1.printStudent();
	s2.printStudent();

	//s1 = s2 = s3;
}

void test03()
{
	Student s1("a");
	Student s2("b");
	Student s3("c");

	s1 = s2 = s3;//赋值操作

	cout << &(s2 = s3) << endl;
	cout << &s2 << endl;
}

int main()
{
	//test02();
	test03();
	system("pause");
	return EXIT_SUCCESS;
}

关系运算符重载

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class Maker
{
public:
	Maker()
	{
		id = 0;
		age = 0;
	}
	Maker(int id, int age)
	{
		this->id = id;
		this->age = age;
	}
	bool operator==(Maker &m)
	{
		if (this->id == m.id && this->age == m.age)
		{
			return true;
		}
		return false;
	}
	bool operator != (Maker &m)
	{
		if (this->id != m.id && this->age != m.age)
		{
			return true;
		}
		return false;
	}
public:
	int id;
	int age;
};

void test01()
{
	Maker p1(1, 20);
	Maker p2;
	if (p1 == p2)
	{
		cout << "真" << endl;
	}
	else
	{
		cout << "假" << endl;
	}

	if (p1 != p2)
	{
		cout << "真" << endl;
	}
	else
	{
		cout << "假" << endl;
	}
}

int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

前置加加和后置加加

/你的第二个operator++返回了一个临时变量,这个在C++里面是一个右值(简单来说就是只能放在 = 号右边)
而你重载的 << 操作符号第二个参数是一个非const的引用,非const的引用需要一个左值(可以放在 = 号左边,可以赋值)来初始化,因此报错
解决办法很简单,把你重载的 << 符号第二个参数加上const修饰即可。加了const修饰的引用可以用右值来初始化
/

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;
#include 

void test()
{
	int a = 1;
	cout << ++a << endl;
	cout << a++ << endl;
	cout << a << endl;
	++(++a);
}

class Maker
{
	friend ostream &operator<<(ostream &out,  Maker const  &m);
public:
	Maker(int a)
	{
		this->a = a;
		//cout << "1" << endl;
	}

	//重载前置++
	Maker &operator++()
	{
		++this->a;
		return *this;
	}

	//重载后置++
	//这里不用引用  是因为
	//如果返回引用这里是返回局部的引用    在这个函数执行完时,被释放掉了
	Maker operator++(int)//区分后置++  //占位参数,必须是int
	{
		//后置++,先返回,后++
		Maker tmp(*this);  //1、*this里面的值a是等于2的
		++this->a;   //这个对象的a是等于3的
		return tmp;//返回的是右值常量  零时变量  调用一次构造函数
	
		/*你的第二个operator++返回了一个临时变量,这个在C++里面是一个右值(简单来说就是只能放在 = 号右边)
		而你重载的 << 操作符号第二个参数是一个非const的引用,非const的引用需要一个左值(可以放在 = 号左边,可以赋值)来初始化,因此报错
		解决办法很简单,把你重载的 << 符号第二个参数加上const修饰即可。加了const修饰的引用可以用右值来初始化*/

		/*	cout << "后置加加" << endl;
		return Maker(10);*/
	}

private:
	int a;
};

ostream &operator<<(ostream &out, Maker const  &m)
{
	out << m.a << endl;
	return out;
}

void test01()
{
	Maker m1(1);
	//cout << m1 << endl;//1
	//cout << ++m1 << endl;//2

	cout << (m1++) << endl;//2    
	//cout << m1 << endl;//3  
}

int main()
{
	
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

数组下标重载

MyArray.h

#pragma once
#include
using namespace std;
class MyArray
{
public:
	MyArray();
	//拷贝构造
	MyArray(const MyArray &arr);
	MyArray(int capacity, int val = 0);
	//重写赋值运算符重载函数
	MyArray &operator=(const MyArray &m);

	//要能当左右值
	int &operator[](int index);

	~MyArray();

	//头插
	void PushFront(int val);
	//尾插
	void PushBack(int val);
	//头删
	void PopFront();
	//尾删
	void PopBack();
	//获取数组元素个数
	int Size();
	//获取数组容量
	int Capacity();
	//指定位置插入元素
	void Insert(int pos, int val);
	//获取指定位置的值
	int &Get(int pos);//返回引用可以当左值 又可以当右值
	//在指定位置修改值
	void Set(int pos, int val);

private:
	int *pArray;//指向堆区空间,存储数据
	int mSize;//元素个数
	int mCapacity;//容量
};


MyArray.cpp

#include "MyArray.h"
MyArray::MyArray()
{
	this->mCapacity = 20;
	this->mSize = 0;

	this->pArray = new int[this->mCapacity];
	//初始化
	for (int i = 0; i < this->mCapacity; i++)
	{
		this->pArray[i] = 0;
	}
}

//深拷贝
MyArray::MyArray(const MyArray &arr)
{
	this->mCapacity = arr.mCapacity;
	this->mSize = arr.mSize;
	//申请空间
	this->pArray = new int[arr.mCapacity];
	//拷贝数据
	for (int i = 0; i < this->mSize; i++)
	{
		this->pArray[i] = arr.pArray[i];
	}
}

//MyArray::MyArray(int capacity, int val = 0)//err
//声明和实现只能有一个默认参数
MyArray::MyArray(int capacity, int val)
{
	this->mCapacity = capacity;
	this->mSize = capacity;
	this->pArray = new int[capacity];
	for (int i = 0; i < this->mSize; i++)
	{
		this->pArray[i] = val;
	}
}

MyArray::~MyArray()
{
	if (this->pArray != NULL)
	{
		delete[] this->pArray;
		this->pArray = NULL;
	}
}

//头插
void MyArray::PushFront(int val)
{
	//判断容量是否满
	if (this->mSize == this->mCapacity)
	{
		return;
	}

	for (int i = this->mSize - 1; i >= 0; i--)
	{
		this->pArray[i + 1] = this->pArray[i];
	}
	//空出了0的位置
	this->pArray[0] = val;
	//维护元素个数
	this->mSize++;
}

//尾插
void MyArray::PushBack(int val)
{
	//判断容量是否满
	if (this->mSize == this->mCapacity)
	{
		return;
	}
	this->pArray[this->mSize] = val;
	this->mSize++;
}

//头删   后面的数往前移动来覆盖第一个元素
void MyArray::PopFront()
{
	if (this->mSize == 0)
	{
		return;
	}
	for (int i = 0; i < this->mSize - 1; i++)
	{
		this->pArray[i] = this->pArray[i + 1];
	}
	this->mSize--;
}

//尾删
void MyArray::PopBack()
{
	if (this->mSize == 0)
	{
		return;
	}
	this->mSize--;
}

//获取数组元素个数
int MyArray::Size()
{
	return this->mSize;
}

//获取数组容量
int MyArray::Capacity()
{
	return this->mCapacity;
}

//指定位置插入元素
void MyArray::Insert(int pos, int val)
{
	//判断容量是否满
	if (this->mSize == this->mCapacity)
	{
		return;
	}

	//如果位置不合法,就插入到尾部
	if (pos<0 || pos>this->mSize - 1)
	{
		pos = this->mSize;
	}
	for (int i = this->mSize - 1; i >= pos; i--)
	{
		this->pArray[i + 1] = this->pArray[i];
	}
	//pos的位置空出
	this->pArray[pos] = val;
	this->mSize++;
}

//获取指定位置的值  //返回引用可以当左值 又可以当右值
int &MyArray::Get(int pos)
{
	return this->pArray[pos];
}

//在指定位置修改值
void MyArray::Set(int pos, int val)
{
	if (pos < 0 || pos > this->mCapacity - 1)
	{
		return;
	}

	this->pArray[pos] = val;
}

//重写赋值运算符重载函数
MyArray &MyArray::operator=(const MyArray &m)
{
	cout << "赋值函数" << endl;
	if (this->pArray != NULL)
	{
		delete[] this->pArray;
		this->pArray = NULL;
	}
	this->mCapacity = m.mCapacity;
	this->mSize = m.mSize;
	//2、申请堆区空间,大小由stu决定
	this->pArray = new int[m.mCapacity];
	//3、拷贝数据
	//for (int i = 0; i < this->mSize; i++)//err
	cout << "this->mSize=" << this->mSize << endl;
	for (int i = 0; i < this->mCapacity; i++)
	{
		this->pArray[i] = m.pArray[i];
	}
	//4、返回对象本身
	return *this;
}

//要能当左右值
int &MyArray::operator[](int index)
{
	if (this->mSize <= index)
	{
		this->mSize++;
	}
	return this->pArray[index];
}

62 数组下标运算符重载

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;
#include"MyArray.h"

void test01()
{
	MyArray arr;
	for (int i = 0; i < 20; i++)
	{
		arr[i] = i + 10;
	}

	for (int i = 0; i < 20; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}

void test02()
{
	MyArray arr;
	for (int i = 0; i < 20; i++)
	{
		arr[i] = i + 10;
	}

	for (int i = 0; i < 20; i++)
	{
		cout << arr[i] << " ";
	}

	MyArray arr2;
	arr2 = arr;
	for (int i = 0; i < 20; i++)
	{
		cout << arr2[i] << " ";
	}
	cout << endl;
	cout << arr2.Size() << endl;
}

int main()
{
	test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

c++学习——函数重载、运算符重载_第4张图片

函数调用运算符重载

#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
using namespace std;
//函数调用运算符重载

//打印输出类
class MyPrint
{
public:
	//重载函数调用运算符
	void operator()(string test)
	{
		cout << test << endl;
	}
};

void MyPrint02(string test)
{
	cout << test << endl;
}

void test01()
{
	MyPrint myPrint;

	myPrint("hello world");//由于使用起来类似于函数调用,因此称为仿函数
	MyPrint02("hello world");
}

//仿函数非常灵活,没有固定写法
//加法类

class MyAdd
{
public:
	int operator()(int num1, int num2)
	{
		return num1 + num2;
	}
};

void test02()
{
	MyAdd myadd;
	int ret = myadd(100, 100);
	cout << "ret=" << ret << endl;
	//匿名函数对象  仿函数  
	cout << MyAdd()(100, 100) << endl;
}

int main()
{
	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

你可能感兴趣的:(c++学习,c++,学习,开发语言)