C++初阶讲解—运算符重载汇总+实例(下)

目录

数组下标重载

例子1:数组类

例子2:字符串类

运算符重载三种方式


数组下标重载

表示容器的类通常可以通过元素在容器中的位置访问元素,这些类一般会定义下标运算符operator []

  • 下标运算符必须是成员函数

如果一个类包含下标运算符,那么它通常会定义两个版本:一个返回普通引用,另一个是类的常量成员并且返回常量引用

返回值类型 & operator[ ] (参数);
const 返回值类型 & operator[ ] (参数) const;

使用第一种声明方式,[ ]不仅可以访问元素,还可以修改元素。使用第二种声明方式,[ ]只能访问而不能修改元素。在实际开发中,我们应该同时提供以上两种形式,这样做是为了适应 const 对象,因为通过 const 对象只能调用 const 成员函数,如果不提供第二种形式,那么将无法访问 const 对象的任何元素

#include 
using namespace std;

class Array{
public:
    Array(int length = 0);
    ~Array();
public:
    int & operator[](int i);
    const int & operator[](int i) const;
public:
    int length() const { return m_length; }
    void display() const;
private:
    int m_length;  //数组长度
    int *m_p;  //指向数组内存的指针
};

Array::Array(int length): m_length(length){
    if(length == 0){
        m_p = NULL;
    }else{
        m_p = new int[length];
    }
}

Array::~Array(){
    delete[] m_p;
}

int& Array::operator[](int i){
    return m_p[i];
}

const int & Array::operator[](int i) const{
    return m_p[i];
}

void Array::display() const{
    for(int i = 0; i < m_length; i++){
        if(i == m_length - 1){
            cout<>n;

    Array A(n);
    for(int i = 0, len = A.length(); i < len; i++){
        A[i] = i * 5;
    }
    A.display();
   
    const Array B(n);
    cout<

需要说明的是,B 是 const 对象,如果 Array 类没有提供 const 版本的operator[ ],那么编译器就会报错。虽然只是读取对象的数据,并没有试图修改对象,但是它调用了非 const 版本的operator[ ],编译器不管实际上有没有修改对象,只要是调用了非 const 的成员函数,编译器就认为会修改对象(至少有这种风险)。

例子1:数组类

在.h文件中将数组类的功能和成员进行声明

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include //引入头文件
#include//C++中的字符串
using namespace std; //标准命名空间
class MyArray
{
public:
	MyArray();
	//拷贝函数,防止浅拷贝,因为有pArray需要开辟堆区空间
	MyArray(const MyArray& arr);
	MyArray(int capacity, int val = 0);//有参构造
	//重写赋值运算符重载函数
	MyArray& operator = (const MyArray& m);
	//要能当左右值
	int& operator[](int dex);
	~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;//容量
};

在.c文件中对声明的函数进行封装,并进行测试

#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()
{
	if (this->pArray != NULL)
	{
		delete[] this->pArray;
		this->pArray = NULL;
	}
}
//拷贝构造函数
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)
{
	this->mCapacity = capacity;
	this->mSize = capacity;
	this->pArray = new int[capacity];
	for (int i = 0; i < this->mSize; i++)
	{
		this->pArray[i] = val;
	}
}
//头插法
void MyArray::PushFront(int val)
{
	//判断容量是否已经满了
	if (this->mSize == this->mCapacity)
	{
		return;
	}
	//头插法,数组元素全部后移
	for (int j = this->mSize - 1; j >= 0; j--)
	{
		this->pArray[j + 1] = this->pArray[j];
	}
	//空出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 < 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->mCapacity)
	{
		pos = this->mSize;
	}
	for (int i = this->mSize - 1; i >= pos; i++) {
		this->pArray[i + 1] = this->pArray[i];
	}
	this->pArray[pos] = val;
	//将pos的位置空出来
	this->mSize++;
}
//获取指定位置的值
int& MyArray::Get(int pos)
{
	return this->pArray[pos];
}
//在指定位置修改
void MyArray::Set(int pos, int val)
{
	if (pos<0 || pos>mCapacity - 1)
	{
		return;
	}
	this->pArray[pos] = val;
}
//重写赋值运算符重载函数
MyArray& MyArray::operator=(const MyArray& m)
{
	//1.释放原来的空间
	if (this->pArray != NULL)
	{
		delete[] this->pArray;
		this->pArray = NULL;
	}
	this->mCapacity = m.mCapacity;
	this->mSize = m.mSize;
	//2.申请空间,大小m决定
	this->pArray = new int[m.mCapacity];
	//3.拷贝数据
	for (int i = 0; i < this->mCapacity; i++)
	{
		this->pArray[i] = m.pArray[i];
	}
	return *this;
}
//重写下标[]//要能当左值
int& MyArray::operator[](int i)
{
	//赋值的时候++
	/*
	for (int i = 0; i < 20; i++)
	{
		arr[i] = i + 10;
	}
	for (int i = 0; i < 20; i++)
	{
		cout << arr[i] << endl;
	}
	*/
	//this->mSize++;
	if (this->mSize <= i)
	{
		this->mSize++;
	}
	return this->pArray[i];
}
void printMyArray(MyArray& arr)
{
	for (int i = 0; i < arr.Size(); i++)
	{
		cout << arr.Get(i) << " ";
		cout << endl;
	}
}
void test01()
{
	MyArray arr(20, 1);//调用有参构造
	printMyArray(arr);
	//修改数组中的值
	for (int i = 0; i < arr.Size(); i++)
	{
		arr.Get(i) = i + 100;
	}
	printMyArray(arr);
	//指定位置修改值
	arr.Set(2, 0);
	printMyArray(arr);
	//测试是否发生浅拷贝
	MyArray arr2 = arr;
	printMyArray(arr2);
}
void test02()
{
	MyArray arr;
	//添加元素
	for (int i = 0; i < 10; i++)
	{
		//尾插
		arr.PushBack(i + 10);
	}
	//头插
	for (int i = 0; i < 9; i++)
	{
		arr.PushFront(i + 20);
	}
	//指定位置插入
	arr.Insert(10, 100);
	//打印
	printMyArray(arr);
	arr.PopBack();
	arr.PopFront();
	printMyArray(arr);
}
int main()
{
	test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

例子2:字符串类

在.h文件中将字符串类的功能和成员进行声明

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include //引入头文件
#include//C++中的字符串
using namespace std; //标准命名空间
//要重载的内容
/*
	MyString s1;
	MyString s1;
	MyString s3=s1+s2;重载加号,拷贝构造
	MyString s3=s1+“hello”;重载加号
	s4+=s3 重载+=
	s4+="hello" 重载+=
	cout<>s4;重载>>
*/
class MyString
{
	friend ostream& operator<<(ostream& out, MyString& str);
	friend istream& operator>>(istream& in, MyString& str);
public:
	MyString();
	//用户可以设定初始化字符串,n个c组成的字符串
	MyString(int n, char c);
	MyString(const MyString& str);
	MyString& operator=(const MyString& str);
	MyString operator+(const MyString& str);
	MyString operator+(const char* s);
	MyString& operator+=(const MyString& str);
	MyString& operator+=(const char* s);
	int Size();
	char& operator[](int index);
	~MyString();
private:
	char* pM;//指向堆区空间
	int mSize;
};

在.c文件中对声明的函数进行封装,并进行测试

#include "Mystring.h"
//用户可以设定初始化字符串,n个c组成的字符串
MyString::MyString()
{
	this->pM = new char[1];
	this->pM[0] = '\0';
	this->mSize = 0;
}
//有参构造
MyString::MyString(int n, char c)
{
	//多留出一个位置最后加上'\0'
	this->pM = new char[n+1];
	for (int i = 0; i < n; i++)
	{
		this->pM[i] = c;
	}
	this->pM[n] = '\0';
	this->mSize = n;
}
//拷贝构造
MyString::MyString(const MyString& str)
{
	this->pM = new char[strlen(str.pM) + 1];
	strcpy(this->pM, str.pM);
	this->mSize = str.mSize;
}
//赋值操作,返回原来的对象
MyString& MyString::operator=(const MyString& str)
{
	//1.释放原来的空间
	delete[] this->pM;
	this->pM = NULL;
	//2.申请空间
	this->pM = new char[strlen(str.pM) + 1];
	//3.拷贝数据
	strcpy(this->pM, str.pM);
	this->mSize = str.mSize;
	return *this;
}
MyString MyString::operator+(const MyString& str)
{
	//s3=s1+s2,this是s1,str是s2
	//1.获取s2要开辟的空间大小
	int newlen = this->mSize + str.mSize + 1;
	//2.定义一个临时变量
	MyString tmp;
	if (tmp.pM != NULL)
	{
		//2.释放原来的空间
		delete[] tmp.pM;
		tmp.pM = NULL;
	}
	//3.申请新的空间
	tmp.pM = new char[newlen];
	memset(tmp.pM, 0, newlen);
	tmp.mSize = this->mSize+str.mSize;
	//4.追加字符到空间当中
	strcat(tmp.pM, this->pM);
	strcat(tmp.pM, str.pM);
	return tmp;//返回的时候会调用拷贝构造
}
MyString MyString::operator+(const char *s)
{
	int newlen = this->mSize + strlen(s);
	//开辟空间
	char* newspace = new char[newlen + 1];
	memset(newspace, 0, newlen + 1);
	//追加数据到空间
	strcat(newspace, this->pM);
	strcat(newspace, s);

	MyString temp;
	if (temp.pM != NULL)
	{
		delete[] temp.pM;
		temp.pM = NULL;
	}
	temp.pM = newspace;
	temp.mSize = newlen;
	return temp;
}
MyString& MyString::operator+=(const MyString& str)
{
	/*
		s4+=s3;
	*/
	//1.获取两个字符串的总字符个数
	int newlen = this->mSize + str.mSize;
	//2.申请新空间
	char* newspace = new char[newlen + 1];
	memset(newspace, 0, newlen + 1);
	//3.追加数据
	strcat(newspace, this->pM);
	strcat(newspace, str.pM);
	//4.释放本身的空间
	if (this->pM!= NULL)
	{
		this->pM = NULL;
	}
	this->pM = newspace;
	this->mSize = newlen;
	return *this;
}
MyString& MyString::operator+=(const char* s)
{
	//1.获取两个字符串的总字符个数
	int newlen = this->mSize + strlen(s);
	//2.申请新空间
	char* newspace = new char[newlen + 1];
	memset(newspace, 0, newlen + 1);
	//3.追加数据
	strcat(newspace, this->pM);
	strcat(newspace, s);
	//4.释放本身的空间
	if (this->pM != NULL)
	{
		this->pM = NULL;
	}
	this->pM = newspace;
	this->mSize = newlen;

	return *this;
}
int MyString::Size()
{
	return this->mSize;
}
char& MyString::operator[](int index)
{
	return this->pM[index];
}
MyString::~MyString()
{
	if (this->pM != NULL)
	{
		delete[] this->pM;
		pM = NULL;
	}
}
//并不是类的成员函数
ostream& operator<<(ostream& out, MyString& str)
{
	cout << str.pM;
	return out;
}
istream& operator>>(istream& in, MyString& str)
{
	//cin>>s4
	//用户输入的字符串要储存到s4.pM指向的堆区空间
	//1.定义临时空间
	char tmp[1024] = { 0 };
	//2.获取用户输入的信息
	in >> tmp;
	//3.释放s4的空间
	if (str.pM != NULL)
	{
		delete[] str.pM;
		str.pM = NULL;
	}
	//4.申请新的空间
	str.pM = new char[strlen(tmp) + 1];
	memset(str.pM, 0, strlen(tmp) + 1);
	//5.拷贝用户输入的信息到堆区空间
	strcpy(str.pM, tmp);
	str.mSize = strlen(tmp);
	return in;
}
//测试
void test()
{
	MyString s1(10, 'a');
	cout << s1 << endl;
	MyString s2(3, 'b');
	cout << s2 << endl;
	MyString s3 = s1 + s2;
	cout << s3 << endl;
	MyString s4 = s3 + "hello";
	cout << s4 << endl;
	for (int i = 0; i < s4.Size(); i++)
	{
		cout << s4[i] << endl;
	}
}
int main()
{
	test();
	system("pause");
	return EXIT_SUCCESS;
}

运算符重载三种方式


运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,简化操作 让已有的运算符 适应不同的数据类型。

运算符重载其实就是定义一个函数,在函数体内实现想要的功能,当用到该运算符时,编译器会自动调用这个函数。也就是说,运算符重载是通过函数实现的,它本质上是函数重载。

语法:函数的名字由关键字operator及其紧跟的运算符组成 ,比如:重载+运算符 ==>operator+ 重载=号运算 ==>operator=

注意:重载运算符 不要更改 运算符的本质操作(+是数据的相加 不要重载成相减)。

 

你可能感兴趣的:(c++)