本文主要是分数加法减法为例说明:无参构造、有参构造、拷贝构造函数(复制构造函数)、=赋值操作符重载(赋值构造函数)、-操作符重载,重载为成员函数、+操作符重载,重载为友元函数、++操作符重载,重载为成员函数以及两个数的最大公约数计算方法。
注意事项
1.C++规定,赋值操作符“=”只能重载为成员函数;
2.操作符重载不能改变原操作符的优先级;
3.操作符重载不能改变操作数的个数;
4.操作符重载不能改变操作符的原有语义。
本类是以分数类说明构造函数和操作符重载的,之中两个私有变量m_a、m_b分别是分数的分子和分母。
Header.h头文件
#pragma once
#include <iostream>
#include <stdio.h>
#include "base.h" //头文件链接 https://blog.csdn.net/qq_35118533/article/details/105411376
#include <string.h>
using namespace std;
class Rational {
public:
Rational();//无参构造
~Rational();//析构函数
Rational(int a, int b); //有参构造
//Rational(int a, int b) :m_a(a), m_b(b){ }
//拷贝构造函数(复制构造函数)
Rational(const Rational &cp_val);
// Rational(Rational cp_val); //**error1**
//=赋值操作符重载(赋值构造函数)
Rational &operator = (const Rational &val);
//Rational operator = (Rational val); //**error2**
//-操作符重载,重载为成员函数
Rational operator - (const Rational &val);
//+操作符重载,重载为友元函数
friend Rational operator + (const Rational &val1, const Rational &val2);
//++操作符重载,重载为成员函数
Rational &operator ++ ();
//打印函数,有一个重载版本
const void myprint();
const void myprint(const Rational &val);
//计算最大公约数
inline int caclMaxCommonDivisor(const Rational &val);
private:
int m_a; //分子
int m_b; //分母
};
error1、error2行的代码,GCC和VS均通不过。根据《剑指Offer》上的解释,上述程序中的拷贝构造函数error1、error2传入的参数是Rational 的一个实例,所以由于是传值参数,我们把形参复制到实参会调用拷贝构造函数。因此如果允许拷贝构造函数传值,就会在拷贝构造函数内调用复制构造函数,就会形成无休止的递归调用从而导致栈溢出。
Source.cpp文件
#include <iostream>
#include "Header.h"
//无参构造
Rational::Rational() {
m_a = 0;
m_b = 1;
}
//析构函数
Rational::~Rational() {
std::cout << "destructor" << std::endl;
}
//有参构造
Rational::Rational(int a, int b) {
cout << "constructor with argument "<< endl;
//因为b为分母,所以b不能为0,此处只为演示,具体要求看业务背景
if(0==b){
std::cout << "b=0非法,系统已将其改为1";
b = 1;
}
m_a = a;
m_b = b;
}
//拷贝构造函数
Rational::Rational(const Rational &cp_val) {
cout << "copy constructor " << endl;
m_a = cp_val.m_a;
m_b = cp_val.m_b;
}
//赋值操作符
Rational &Rational::operator = (const Rational &val) {
cout << "= assignment operator " << endl;
m_a = val.m_a;
m_b = val.m_b;
return *this;
}
//++操作符重载,重载为成员函数
Rational &Rational::operator ++ () {
cout << "++ assignment operator " << endl;
m_a += m_b;
//++m_b;
return *this;
}
//+操作符重载,重载为友元函数
Rational operator + (const Rational &val1, const Rational &val2) {
cout << "+ assignment operator ";
//只有lvalue才能被赋值, a*val.a是一个表达式结果为右值,编译报错,实际上这行代码逻辑也不对
//a*val.b += val.a*b; //error 当时犯的错误没有删掉给大家提个醒,不要再出现类似错误
Rational tmp;
tmp.m_a = val1.m_a*val2.m_b + val1.m_b * val2.m_a;
tmp.m_b = val1.m_b*val2.m_b;
int maxDiv = tmp.caclMaxCommonDivisor(tmp);
tmp.m_a /= maxDiv;
tmp.m_b /= maxDiv;
return tmp;
}
//-操作符重载,重载为成员函数
Rational Rational::operator - (const Rational &val) {
cout << "- assignment operator ";
Rational tmp;
tmp.m_a = this->m_a*val.m_b - val.m_a * this->m_b;
tmp.m_b = this->m_b*val.m_b;
int maxDiv = tmp.caclMaxCommonDivisor(tmp);
//std::cout <<" " << maxDiv << " ";
//tmp.myprint();
tmp.m_a /= maxDiv;
tmp.m_b /= maxDiv;
return tmp;
}
//打印函数
const void Rational::myprint(const Rational &val) {
std::cout << val.m_a << "/" << val.m_b;
std::cout << std::endl;
return;
}
//重载打印函数
const void Rational::myprint() {
std::cout << m_a << "/" << m_b;
std::cout << std::endl;
return;
}
//计算最大公约数 将分数的分子和分母看作两个两个数,计算这两个数的最大公约数
//此方法叫“辗转相除法”,而中国《九章算术》的更相减损法也可计算
inline int Rational::caclMaxCommonDivisor(const Rational &val) {
int tmp_r = 0, tmp_a = val.m_a, tmp_b = val.m_b;
if (val.m_a < 0) {
tmp_a = -tmp_a;
}
while (tmp_b != 0) {
tmp_r = tmp_b;
tmp_b = tmp_a % tmp_b;
if (0 == tmp_b)break;
tmp_a = tmp_r;
}
return tmp_r;
}
主函数 main.cpp
演示作用,调用类中函数进行说明和演示
#include <iostream>
#include "Header.h"
int main() {
Rational test(99, 100);
test.myprint();
Rational test1 = test;
test1.myprint();
Rational test2(test);
//test2(test); //error ()没有重载
Rational a;
PRINTF_DBG(" a=");
a.myprint(a);
Rational b(1, 2);
PRINTF_DBG(" b=");
b.myprint();
Rational c(3, 4);
PRINTF_DBG(" c=");
c.myprint();
Rational d(5, 6);
PRINTF_DBG(" d=");
d.myprint();
Rational e;
PRINTF_DBG(" e=");
e.myprint();
e = a + b + c + d;
a.myprint();
PRINTF_DBG(" e=");
e.myprint();
e = a;
PRINTF_DBG(" e=");
e.myprint();
e = a - b - c - d;
e.myprint();
for (size_t i = 0; i < 5; i++){
++e;
e.myprint();
}
getchar();
return 0;
}
运算结果:
2. 当某对象没被初始化,这时运用赋值运算符调用的是拷贝构造函数;否则调用的是赋值运算符重载函数;
参考文献:
https://www.cnblogs.com/alantu2018/p/8459250.html