Skip to content

Latest commit

 

History

History
153 lines (111 loc) · 5.06 KB

9.2a — Overloading operators using normal functions.md

File metadata and controls

153 lines (111 loc) · 5.06 KB

9.2a — Overloading operators using normal functions

In the previous lesson, we overloaded operator+ as a friend function:

#include <iostream>
 
class Cents
{
private:
  int m_cents{};
 
public:
  Cents(int cents)
    : m_cents{ cents }
  {}
 
  // add Cents + Cents using a friend function
  friend Cents operator+(const Cents &c1, const Cents &c2);
 
  int getCents() const { return m_cents; }
};
 
// note: this function is not a member function!
Cents operator+(const Cents &c1, const Cents &c2)
{
  // use the Cents constructor and operator+(int, int)
  // we can access m_cents directly because this is a friend function
  return { c1.m_cents + c2.m_cents };
}
 
int main()
{
  Cents cents1{ 6 };
  Cents cents2{ 8 };
  Cents centsSum{ cents1 + cents2 };
  std::cout << "I have " << centsSum.getCents() << " cents.\n";
 
  return 0;
}

Using a friend function to overload an operator is convenient because it gives you direct access to the internal members of the classes you’re operating on. In the initial Cents example above, our friend function version of operator+ accessed member variable m_cents directly.

使用友元函数来重载运算符是非常方便的,因为友元函数可以直接访问类内的私有成员。

However, if you don’t need that access, you can write your overloaded operators as normal functions. Note that the Cents class above contains an access function (getCents()) that allows us to get at m_cents without having to have direct access to private members. Because of this, we can write our overloaded operator+ as a non-friend:

然而如果你不需要那种访问权限(访问私有成员的权限)的话,你可以像写普通函数那样去重载运算符,可以通过公开的成员函数来完成重载的过程。

#include <iostream>
 
class Cents
{
private:
  int m_cents{};
 
public:
  Cents(int cents)
    : m_cents{ cents }
  {}
 
  int getCents() const { return m_cents; }
};
 
// note: this function is not a member function nor a friend function!
Cents operator+(const Cents &c1, const Cents &c2)
{
  // use the Cents constructor and operator+(int, int)
  // we don't need direct access to private members here
  return Cents{ c1.getCents() + c2.getCents() };
}
 
int main()
{
  Cents cents1{ 6 };
  Cents cents2{ 8 };
  Cents centsSum{ cents1 + cents2 };
  std::cout << "I have " << centsSum.getCents() << " cents.\n";
 
  return 0;
}

Because the normal and friend functions work almost identically (they just have different levels of access to private members), we generally won’t differentiate them. The one difference is that the friend function declaration inside the class serves as a prototype as well. With the normal function version, you’ll have to provide your own function prototype.

普通的函数和友元函数工作起来几乎完全一样,只是有访问级别的区别,通常我们不分辨两者。有一个不同点是对于友元函数,你需要在类里面写一个友缘声明,但是对于普通的函数,你可能需要写一个函数原型(或者在某些情况下不需要写)。

Cents.h:

class Cents
{
private:
  int m_cents{};
 
public:
  Cents(int cents)
    : m_cents{ cents }
  {}
  
  int getCents() const { return m_cents; }
};
 
// Need to explicitly provide prototype for operator+ so uses of operator+ in other files know this overload exists
Cents operator+(const Cents &c1, const Cents &c2);

Cents.cpp:


#include "Cents.h"
 
// note: this function is not a member function nor a friend function!
Cents operator+(const Cents &c1, const Cents &c2)
{
  // use the Cents constructor and operator+(int, int)
  // we don't need direct access to private members here
  return { c1.getCents() + c2.getCents() };
}

main.cpp:


#include "Cents.h"
#include <iostream>
 
int main()
{
  Cents cents1{ 6 };
  Cents cents2{ 8 };
  Cents centsSum{ cents1 + cents2 }; // without the prototype in Cents.h, this would fail to compile
  std::cout << "I have " << centsSum.getCents() << " cents.\n";
 
  return 0;
}

In general, a normal function should be preferred over a friend function if it’s possible to do so with the existing member functions available (the less functions touching your classes’s internals, the better). However, don’t add additional access functions just to overload an operator as a normal function instead of a friend function!

在大部分情况下我们更应该选择普通函数实现运算符重载而不是友元函数,如果有已有的类成员函数能满足需要的话。

应该尽可能不要碰类的内部。但是也不要为了去做一个普通函数的重载运算符实现而添加一些类成员函数。

Rule

Prefer overloading operators as normal functions instead of friends if it’s possible to do so without adding additional functions.

尽可能不要用友元函数来重载运算符,使用普通的函数来实现。其实就是不要在类里面去注册一个函数成为你的朋友