C++进阶:使用普通函数重载算数运算符
一般来说,如果可以利用现有的成员函数(接触类内部的函数越少越好),则应优先使用普通函数而不是友元函数。但是,不要仅仅为了将运算符重载为普通函数而不是友元函数而添加额外的访问函数
单文件 main.cpp
1 #include <numeric> // for std::gdb2 #include <iostream>34 class Fraction5 {6 private:7 int m_numerator {};8 int m_denominator { };910 public:11 explicit Fraction(int numerator, int denominator = 1)12 : m_numerator{ numerator }, m_denominator{ denominator }13 { }1415 16 int getNumerator() const17 {18 return m_numerator;19 }2021 int getDenominator() const22 {23 return m_denominator;24 }2526 void reduce();27 void print();28 };2930 Fraction operator*(const Fraction& f1, const Fraction& f2);31 Fraction operator*(const Fraction& f1, int value);32 Fraction operator*(int value, const Fraction& f1);3334 Fraction operator*(const Fraction& f1, const Fraction& f2)35 {36 return Fraction{ f1.getNumerator() * f2.getNumerator(), f1.getDenominator() * f2.getDenominator() };37 }383940 Fraction operator*(const Fraction& f1, int value)41 {42 return Fraction{ f1.getNumerator() * value, f1.getDenominator() };43 }4445 Fraction operator*(int value, const Fraction& f1)46 {47 return Fraction{ f1.getNumerator() * value, f1.getDenominator() };48 }4950 void Fraction::reduce()51 {52 int m_gcd{ std::gcd(m_numerator, m_denominator) };53 if (m_gcd) // Make sure we don't try to divide by 054 {55 m_numerator /= m_gcd;56 m_denominator /= m_gcd;57 }58 }59 void Fraction::print()60 {61 Fraction::reduce();62 std::cout << m_numerator<< "/" << m_denominator << '\n';63 }6465 int main()66 {67 Fraction f1{ 1, 4};68 f1.print();6970 Fraction f2{ 1, 2 };71 f2.print();7273 Fraction f3{ f1 * f2 };74 f3.print();7576 Fraction f4{ 2 * f1 };77 f4.print();7879 Fraction f5{ f1 * 3 };80 f5.print();8182 Fraction f6{ Fraction{1, 2} * Fraction{2, 3} * Fraction{3, 4} };83 f6.print();8485 return 0;86 }87
改写多文件
将类和声明放到头文件里面,为防止单个文件重复使用声明,加上条件编译保护机制。
具体操作:将上面4~32行放到Fraction.h文件加上标识符为FRACTION_H的头文件保护机制
Fraction.h
#ifndef FRACTION_H
#define FRACTION_H
class Fraction
{
private:int m_numerator {};int m_denominator { };public:explicit Fraction(int numerator, int denominator = 1): m_numerator{ numerator }, m_denominator{ denominator }{ }int getNumerator() const{return m_numerator;}int getDenominator() const{return m_denominator;}void reduce();void print();
};Fraction operator*(const Fraction& f1, const Fraction& f2);
Fraction operator*(const Fraction& f1, int value);
Fraction operator*(int value, const Fraction& f1);
#endif
将头文件Fraction.h的具体实现放入到Fration.cpp中,最好包含Fraction.h,表示结构上关系的清晰(不引入自会编译器自会寻找),再包含进所用到的头文件。
具体操作:将34~64行放入Fration.cpp中,因为求两数最大公约数的std::gcd是文件中的,也用到了std::cout,所以和也#include 进去。
Fration.cpp
#include "Fraction.h"
#include <numeric>
#include <iostream>
Fraction operator*(const Fraction& f1, const Fraction& f2)
{return Fraction{ f1.getNumerator() * f2.getNumerator(), f1.getDenominator() * f2.getDenominator() };
}Fraction operator*(const Fraction& f1, int value)
{return Fraction{ f1.getNumerator() * value, f1.getDenominator() };
}Fraction operator*(int value, const Fraction& f1)
{return Fraction{ f1.getNumerator() * value, f1.getDenominator() };
}
void Fraction::reduce()
{int m_gcd{ std::gcd(m_numerator, m_denominator) };if (m_gcd) // Make sure we don't try to divide by 0{m_numerator /= m_gcd;m_denominator /= m_gcd;}
}
void Fraction::print()
{Fraction::reduce();std::cout << m_numerator<< "/" << m_denominator << '\n';
}
剩下的就是main.cpp 了,将Fraction.h包含进来,删掉没用到的头文件就可以了。
main.cpp
#include "Fraction.h"int main()
{Fraction f1{ 1, 4};f1.print();Fraction f2{ 1, 2 };f2.print();Fraction f3{ f1 * f2 };f3.print();Fraction f4{ 2 * f1 };f4.print();Fraction f5{ f1 * 3 };f5.print();Fraction f6{ Fraction{1, 2} * Fraction{2, 3} * Fraction{3, 4} };f6.print();return 0;
}
确保这个三个文件都在同一目录下面,然后就开始编译了。
单独编译各个文件都没有编译方面的问题。
使用lld链接也没有问题,运行可执行文件a.out按照预期输入了化简后的分数。