C++学习笔记(4)——运算符重载实现

上次回顾:

拷贝构造

​ 用对象来构造对象

引用:给内存段取别名

拷贝构造参数必须是引用:

​ 传参过程不会产生临时变量,没有值传递

深拷贝:

​ 开辟内存去拷贝

浅拷贝:

​ 直接值传递

运算符重载:

  1. 运算符的本质:函数

    运算符:具备特殊功能的符号

  2. 运算符重载的本质:

    对象中重载运算符函数

  3. 如何定义(声明)运算符重载

    函数名 operateor 运算符名 ex: operator +

    参数 操作数 左值 和 右值

    返回值 表达式的返回值(具备唯一返回值:1+2)

    函数体

  4. 运算符重载的两种方式

    4.1 重载运算符函数为类的成员函数

    ​ 当前对象为运算符的左值

    ​ 例如:

    ​ f1 (1, 2)

    ​ f2 (3, 6)

    ​ 默认f1为左值 f1 + f2

    question:

    4.2 重载运算符函数为类的友(缘)函数

    ​ 4.2.1 友缘函数不是类的成员函数

    ​ 4.2.2 友缘函数中可以访问成员变量

    // 友元函数.cpp : 定义控制台应用程序的入口点。
    #include "stdafx.h"
    class A {
          
          
    	int n;
    public:
    	A(int n) :n(n) {
          
          }
    
    	void setN(int n) {
          
          
    		this->n = n;
    	}
    	
    	void show() {
          
          
    		printf("n: %d\n", n);
    	}
    	friend void func(A a); //声明友元函数
    };
    
    void func(A a) {
          
          
    	printf("参数的成员变量 n:%d\n", a.n);
    }
    int main()
    {
          
          
    	A a(10);
    	func(a);
    	while (1);
        return 0;
    }
    
  5. 语法和规范

    5.1 语法

    ​ 5.1.1 基本上所有运算符都能重载,除了以下几个

    ​ . -> :: ?: &(取地址) 位运算符一般不重载 sizeof()关键字

    ​ 5.1.2 不能创建新的运算符

    ​ 5.1.3 遵循函数重载原则

    5.2 规范

    ​ 5.2.1 双目运算符一般重载为友元函数,单目运算符一般重载为成员函数(程序更加直观)

    ​ 5.2.2 不能修改运算符的规则:优先级,操作数个数,操作数类型

    ​ 5.2.3 重载后的运算符应和原运算符功能相同

  6. 练习运算符重载

    1. 算术运算符 + - + - * / %

    2. 关系运算符 < > <= >= == !=

    3. 输入输出运算符 只能重载友缘 (左操作数不为当前对象)

      6.3.1 << 输出运算符的

      ​ 第一个参数 cout: ostream 输出流对象

      ​ 返回值

      6.3.2 >>输入运算符的

      ​ 第一个参数 cin: istream 输入流对象

      ​ 返回值

    4. 逻辑运算符

    5. 自运算符 ++ –

      后自增,后自减 参数列表为 int

    6. 赋值运算符 = += -= *= /= …

      6.6.1 编译器缺省定义(不用自定义)

      6.6.2 虽然是双目运算符,但必须重载为成员函数

      6.6.3 注意连续使用只能用相同对象

      6.6.4 区分拷贝构造和赋值运算符重载

    7. new delete

      why 重载这俩货 (手动内存分配是为了节约内存)

      6.7.1 重载动机:

      ​ 手动内存分配需要注意内存泄露问题(申请内存资源未及时释放)

      ​ because:帮助排查内存泄露问题,记录开辟与释放内存大小

      6.6.2

tips:

  1. 成员函数中使用标识符:默认作用域为类
  2. 标识符前加 “::” 作用于为当前文件
// 运算符重载.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"
//extern size_t count;

int main()
{
    
    
	fenshu a(1,2), b(2,3);
	fenshu c(a + b);	//拷贝构造
	fenshu d = b;	//定义(不是赋值操作):调用的是拷贝构造函数,不是赋值运算符重载
	c.show();

#if 0
	cin >> c;	//需要键入分子 分隔符  分母 回车确定
	c.show();
	if (a == b) {
    
    
		cout << "a" << "==" << "b" << endl;
		cout << a << "==" << b << endl;	//注意每个 << 的代表意义不同
	}
	else {
    
    
		cout << "a" << "!=" << "b" << endl;
		cout << a << "!=" << b << endl;
	}

	cout << a++ << endl;
	cout << ++a << endl;
#endif
	a = b;	//编译器缺省定义完成 赋值运算符
	// 上式不能完成对指针的赋值
	fenshu* p = new fenshu(5, 6);
	fenshu* p1 = new fenshu[5]{
    
     {
    
    1,2},{
    
    3,4},{
    
    5,6},{
    
    7,8},{
    
    9,10} };
	//a = *p;	//	*地址可以
	//a = p //不行,需要自定义
	a = p;	//重载 '=' 后 可以
	//a += 1;	//不行,需自定义
	cout << a << endl;
	cout << *(p1 + 1) << endl;
	delete[] p1;
	delete p;
	//!!区分返回值是类还是类的引用比如赋值运算符 =
	/*
	int x, y, z;
	x = y = z = 1;//可连续调用,返回类的引用
	x++ = 1;//++ 出现错误,返回类
	*/
	//排查是否存在内存泄露
	cout << "共开辟释放count:" << ::count << "字节内存" << endl;
	while (1);
    return 0;
}
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// TODO:  在此处引用程序需要的其他头文件
#include<iostream>
using namespace std;
#include"fenshu.h"
#include"tool.h"
//#include<cstdib>
//fenshu.h
#pragma once
extern size_t count;

class fenshu
{
    
    
	int fenzi;
	int fenmu;
public:
	fenshu();
	fenshu(int a, int m); 
	fenshu(const fenshu& fs);
	~fenshu();
	void show() {
    
    
		cout << fenzi << " / " << fenmu << endl;
	}
	//void tongfen() {};
	//fenshu operator + (const fenshu& fs); //返回对象类型
	friend fenshu operator + (const fenshu& fs1, const fenshu& fs2);
	friend bool operator == (const fenshu& fs1, const fenshu& fs2);
	friend ostream& operator << (ostream& os, const fenshu&fs2);
	friend istream& operator >> (istream& is, fenshu& fs2);
	//前自增 ++n
	fenshu operator ++ ();//默认对本对象进行操作
	//后自增 n++
	fenshu operator ++ (int);
	//!!区分返回值是类还是类的引用
	//赋值运算符重载
	//fenshu& operator = (fenshu& fs1, const fenshu& fs2);
	fenshu& operator = (const fenshu& fs);
	fenshu& operator = (const fenshu* p);

	void* operator new(size_t size);
	void  operator delete(void* p,size_t size);
	void* operator new[](size_t size);
	void  operator delete[](void* p, size_t size);
};
//fenshu.cpp
#include "stdafx.h"
#include "fenshu.h"

size_t count = 0;

fenshu::fenshu() {
    
    
	fenzi = 1;
	fenmu = 1;
	cout << "无参构造函数" << endl;
}
fenshu::fenshu(int a,int m)
{
    
    
	fenzi = a;
	fenmu = m;
	cout << "有参构造函数" << endl;
}

fenshu::fenshu(const fenshu& fs) {
    
    
	this->fenmu = fs.fenmu;
	this->fenzi = fs.fenzi;
	cout << "拷贝构造函数" << endl;
}

fenshu::~fenshu()
{
    
    
	cout << "析构函数" << endl;
}
#if 0
fenshu fenshu::operator+(const fenshu& fs) {
    
    
	fenshu temp;
	temp.fenzi = this->fenzi * fs.fenmu + this->fenmu * fs.fenzi;
	temp.fenmu = this->fenmu * fs.fenmu;
	return temp;

}
#endif
//前自增 ++n
fenshu fenshu::operator ++ () {
    
    //默认对本对象进行操作
	cout << "前自增" << endl;
	this->fenzi += this->fenmu;
	return *this;
}
//后自增 n++		int 只是为了区分前后自增
fenshu fenshu::operator ++ (int) {
    
    
	cout << "后自增" << endl;
	fenshu temp;
	temp.fenzi = fenzi;
	temp.fenmu = fenmu;
	this->fenzi += this->fenmu;
	return temp;
}
//!!区分返回值是类还是类的引用
//赋值运算符重载
fenshu& fenshu::operator = (const fenshu& fs) {
    
    
	this->fenzi = fs.fenzi;
	this->fenmu = fs.fenmu;
	cout << "赋值运算符重载" << endl;
	return *this;
}
fenshu& fenshu::operator = (const fenshu* p) {
    
    
	this->fenzi = p->fenzi;
	this->fenmu = p->fenmu;
	return *this;
}
void* fenshu::operator new(size_t size) {
    
    
	printf("申请%d字节内存\n", size);
	::count += size;
	return malloc(size);
}

void fenshu::operator delete(void* p,size_t size) {
    
    
	 printf("释放%d字节内存\n", size);
	 ::count -= size;//加 “::” 代表整个文件的作用域
	 free(p);
	 return;
}
void* fenshu::operator new[](size_t size) {
    
    
	printf("申请%d字节内存\n", size);
	::count += size;
	return malloc(size);
}

void fenshu::operator delete[](void* p, size_t size) {
    
    
	printf("释放%d字节内存\n", size);
	::count -= size;//加 “::” 代表整个文件的作用域
	free(p);
	return;
}
//tool.h
#pragma once
#include"fenshu.h"

fenshu operator + (const fenshu& fs1, const fenshu& fs2);
bool operator == (const fenshu& fs1, const fenshu& fs2);
ostream& operator << (ostream& os, const fenshu& fs2);//输出运算符
//返回值为什么是 ostream引用: 
//需要调用下一个 <<,左操作数还是ostream&
istream& operator >> (istream& is, fenshu& fs2);//输入运算符改变fs2的值

//tool.cpp(友元函数)
#include "stdafx.h"
fenshu operator + (const fenshu& fs1, const fenshu& fs2) {
    
    
	fenshu temp;
	temp.fenzi = fs1.fenzi * fs2.fenmu + fs1.fenmu * fs2.fenzi;
	temp.fenmu = fs1.fenmu * fs2.fenmu;
	return temp;
}
bool operator == (const fenshu& fs1, const fenshu& fs2) {
    
    
	if(fs1.fenzi*fs2.fenmu == fs1.fenmu * fs2.fenzi)return true;
	cout << "==运算符重载" << endl;
	return false;
}
ostream& operator << (ostream& os, const fenshu& fs2) {
    
    //加不加 const?
	return (os << "(" << fs2.fenzi << "/" << fs2.fenmu << ")");
}
istream& operator >> (istream& is, fenshu& fs2) {
    
     //输入运算符会改变fs2的值
	char c;
	return is >> fs2.fenzi >> c >> fs2.fenmu;
}

运行结果:

在这里插入图片描述

题目:实现Mystring类的运算符重载 “+” ,字符串相连

在上一篇文章的MyString.cpp中添加如下代码,先在类中声明该友元函数

MyString& MyString::operator + (const MyString& str) {
    
    
	size_t sumsize = this->size + str.size;
	char* pNew = new char[sumsize +1];
	memcpy(pNew, this->pStr, this->size);
	memcpy(pNew + this->size, str.pStr, str.size + 1);
	delete[] this->pStr;
	this->pStr = pNew;
	this->size = sumsize;
	return *this;
}

主函数中添加:

str1 + str2;
printf("运算符重载%s\n", str1.c_str());

运行结果:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43357695/article/details/105331791