21.3 — Przeciążanie operatorów przy użyciu normalnych funkcji

W poprzedniej lekcji przeciążaliśmy operator+ jako funkcję zaprzyjaźnioną:

#include <iostream>
 
class Cents
{
private:
  int m_cents{};

public:
  Cents(int cents)
    : m_cents{ cents }
  {}

  // dodaj centy + centy za pomocą przyjaciela funkcja
  friend Cents operator+(const Cents& c1, const Cents& c2);

  int getCents() const { return m_cents; }
};
 
// uwaga: ta funkcja nie jest funkcją składową funkcja!
Cents operator+(const Cents& c1, const Cents& c2)
{
  // użyj konstruktora Cents i operatora+(int, int)
  // możemy uzyskać bezpośredni dostęp do m_cents, ponieważ jest to funkcja znajomego
  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;
}

Korzystanie z funkcji zaprzyjaźnionej do przeciążania operatora jest wygodne, ponieważ zapewnia bezpośredni dostęp do wewnętrznych elementów klas, na których operujesz. W powyższym przykładzie z Centami nasza znajoma wersja operatora+ uzyskała bezpośredni dostęp do zmiennej składowej m_cents.

Jeśli jednak nie potrzebujesz takiego dostępu, możesz zapisać przeciążone operatory jako normalne funkcje. Należy zauważyć, że powyższa klasa Cents zawiera funkcję dostępu (getCents()), która pozwala nam uzyskać m_cents bez konieczności posiadania bezpośredniego dostępu do prywatnych członków. Z tego powodu możemy zapisać naszego przeciążonego operatora+ jako nie-przyjaciela:

#include <iostream>

class Cents
{
private:
  int m_cents{};

public:
  Cents(int cents)
    : m_cents{ cents }
  {}

  int getCents() const { return m_cents; }
};

// uwaga: ta funkcja nie jest funkcją składową ani funkcją zaprzyjaźnioną!
Cents operator+(const Cents& c1, const Cents& c2)
{
  // użyj konstruktora Cents i operatora+(int, int)
  // nie potrzebujemy tutaj bezpośredniego dostępu do prywatnych członków
  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;
}

Ponieważ funkcje normalne i zaprzyjaźnione działają prawie identycznie (mają tylko różne poziomy dostępu do elementów prywatnych), generalnie nie będziemy ich rozróżniać. Jedyna różnica polega na tym, że deklaracja funkcji przyjaciela wewnątrz klasy służy również jako prototyp. W przypadku normalnej wersji funkcji będziesz musiał dostarczyć własny prototyp funkcji.

Cents.h:

#ifndef CENTS_H
#define CENTS_H

class Cents
{
private:
  int m_cents{};

public:
  Cents(int cents)
    : m_cents{ cents }
  {}
  
  int getCents() const { return m_cents; }
};

// Należy jawnie podać prototyp operatora+, aby użycie operator+ w innych plikach wiedziało, że istnieje przeciążenie
Cents operator+(const Cents& c1, const Cents& c2);

#endif

Cents.cpp:

#include "Cents.h"

// uwaga: ta funkcja nie jest funkcją składową ani funkcją zaprzyjaźnioną!
Cents operator+(const Cents& c1, const Cents& c2)
{
  // użyj konstruktora Cents i operatora+(int, int)
  // nie potrzebujemy tutaj bezpośredniego dostępu do prywatnych członków
  return { c1.getCents() + c2.getCents() };
}

main.cpp:

#include "Cents.h"
#include <iostream>

int main()
{
  Cents cents1{ 6 };
  Cents cents2{ 8 };
  Cents centsSum{ cents1 + cents2 }; // bez prototypu w Cents.h nie udałoby się tego skompilować
  std::cout << "I have " << centsSum.getCents() << " cents.\n";

  return 0;
}

Ogólnie rzecz biorąc, normalna funkcja powinna być preferowana zamiast funkcji zaprzyjaźnionej, jeśli jest to możliwe przy użyciu istniejących funkcji składowych (im mniej funkcji dotyka elementów wewnętrznych klas, tym lepiej). Nie dodawaj jednak dodatkowych funkcji dostępu tylko po to, aby przeciążyć operatora jako normalną funkcję, a nie funkcję zaprzyjaźnioną!

Najlepsza praktyka

Preferuj przeciążanie operatorów jako normalne funkcje zamiast znajomych, jeśli można to zrobić bez dodawania dodatkowych funkcji.

guest
Twój adres e-mail nie zostanie wyświetlony
Znalazłeś błąd? Zostaw komentarz powyżej!
Komentarze związane z poprawkami zostaną usunięte po przetworzeniu, aby pomóc zmniejszyć bałagan. Dziękujemy za pomoc w ulepszaniu witryny dla wszystkich!
Awatary z https://gravatar.com/ są połączone z podanym adresem e-mail.
Powiadamiaj mnie o odpowiedziach:  
95 Komentarze
Najnowsze
Najstarsze Najczęściej głosowane
Wbudowane opinie
Wyświetl wszystkie komentarze