C++学习笔记(4)——运算符重载实现
上次回顾:
拷贝构造
用对象来构造对象
引用:给内存段取别名
拷贝构造参数必须是引用:
传参过程不会产生临时变量,没有值传递
深拷贝:
开辟内存去拷贝
浅拷贝:
直接值传递
运算符重载:
-
运算符的本质:函数
运算符:具备特殊功能的符号
-
运算符重载的本质:
对象中重载运算符函数
-
如何定义(声明)运算符重载
函数名 operateor 运算符名 ex: operator +
参数 操作数 左值 和 右值
返回值 表达式的返回值(具备唯一返回值:1+2)
函数体
-
运算符重载的两种方式
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.1 语法
5.1.1 基本上所有运算符都能重载,除了以下几个
. -> :: ?: &(取地址) 位运算符一般不重载 sizeof()关键字
5.1.2 不能创建新的运算符
5.1.3 遵循函数重载原则
5.2 规范
5.2.1 双目运算符一般重载为友元函数,单目运算符一般重载为成员函数(程序更加直观)
5.2.2 不能修改运算符的规则:优先级,操作数个数,操作数类型
5.2.3 重载后的运算符应和原运算符功能相同
-
练习运算符重载
-
算术运算符 + - + - * / %
-
关系运算符 < > <= >= == !=
-
输入输出运算符 只能重载友缘 (左操作数不为当前对象)
6.3.1 << 输出运算符的
第一个参数 cout: ostream 输出流对象
返回值
6.3.2 >>输入运算符的
第一个参数 cin: istream 输入流对象
返回值
-
逻辑运算符
-
自运算符 ++ –
后自增,后自减 参数列表为 int
-
赋值运算符 = += -= *= /= …
6.6.1 编译器缺省定义(不用自定义)
6.6.2 虽然是双目运算符,但必须重载为成员函数
6.6.3 注意连续使用只能用相同对象
6.6.4 区分拷贝构造和赋值运算符重载
-
new delete
why 重载这俩货 (手动内存分配是为了节约内存)
6.7.1 重载动机:
手动内存分配需要注意内存泄露问题(申请内存资源未及时释放)
because:帮助排查内存泄露问题,记录开辟与释放内存大小
6.6.2
-
tips:
- 成员函数中使用标识符:默认作用域为类
- 标识符前加 “::” 作用于为当前文件
// 运算符重载.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());
运行结果: