На попередньому уроці ми перевантажували operator+() через дружню функцію:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <iostream> class Dollars { private: int m_dollars; public: Dollars(int dollars) { m_dollars = dollars; } // Виконуємо Dollars + Dollars через дружню функцію friend Dollars operator+(const Dollars &d1, const Dollars &d2); int getDollars() const { return m_dollars; } }; // Примітка: Ця функція не є методом класу! Dollars operator+(const Dollars &d1, const Dollars &d2) { // Використовуємо конструктор Dollars і operator+(int, int). // Ми маємо доступ до закритого члену m_dollars, так як ця функція є дружньою класу Dollars return Dollars(d1.m_dollars + d2.m_dollars); } int main() { Dollars dollars1(7); Dollars dollars2(9); Dollars dollarsSum = dollars1 + dollars2; std::cout << "I have " << dollarsSum.getDollars() << " dollars." << std::endl; return 0; } |
Використання дружньої функції для перевантаження оператора зручно тим, що ми маємо прямий доступ до всіх членів класу, з яким працюємо. У прикладі, наведеному вище, наша дружня функція перевантаження оператора +
має прямий доступ до закритого члену m_dollars
класу Dollars.
Однак, якщо нам не потрібен доступ до членів певного класу, ми можемо перевантажити оператор і через звичайну функцію. Зверніть увагу, в класі Dollars є геттер getDollars(), за допомогою якого ми можемо отримати доступ до m_dollars
ззовні класу. Перепишемо перевантаження оператора +
через звичайну функцію:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#include <iostream> class Dollars { private: int m_dollars; public: Dollars(int dollars) { m_dollars = dollars; } int getDollars() const { return m_dollars; } }; // Примітка: Ця функція не є ні методом класу, ні дружньою класу Dollars! Dollars operator+(const Dollars &d1, const Dollars &d2) { // Використовуємо конструктор Dollars і operator+(int, int). // Тут нам не потрібний прямий доступ до закритих членів класу Dollars return Dollars(d1.getDollars() + d2.getDollars()); } int main() { Dollars dollars1(7); Dollars dollars2(9); Dollars dollarsSum = dollars1 + dollars2; std::cout << "I have " << dollarsSum.getDollars() << " dollars." << std::endl; return 0; } |
Оскільки принцип перевантаження операторів через звичайні і дружні функції майже ідентичний (вони просто мають різні рівні/умови доступу до закритих членів класу), то єдина відмінність полягає в тому, що у випадку з дружньою функцією, її потрібно обов’язково оголосити в класі + визначити поза тілом класу (або в класі), в той час як звичайну функцію досить просто визначити поза тілом класу, без вказівки додаткового прототипу функції.
Dollars.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Dollars { private: int m_dollars; public: Dollars(int dollars) { m_dollars = dollars; } int getDollars() const { return m_dollars; } }; // Вказуємо прототип operator+(), щоб мати можливість використати перевантажений оператор + в інших файлах Dollars operator+(const Dollars &d1, const Dollars &d2); |
Dollars.cpp:
1 2 3 4 5 6 7 8 9 |
#include "Dollars.h" // Примітка: Ця функція не є ні методом класу, ні дружньою класу Dollars! Dollars operator+(const Dollars &d1, const Dollars &d2) { // Використовуємо конструктор Dollars і operator+(int, int). // Тут нам не потрібний прямий доступ до закритих членів класу Dollars return Dollars(d1.getDollars() + d2.getDollars()); } |
main.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <iostream> #include "Dollars.h" int main() { Dollars dollars1(7); Dollars dollars2(9); Dollars dollarsSum = dollars1 + dollars2; // без явної вказівки прототипу operator+() в Dollars.h цей рядок не скомпілювався б std::cout << "I have " << dollarsSum.getDollars() << " dollars." << std::endl; return 0; } |
Для перевантаження операторів рекомендується використовувати звичайні функції, а не дружні, якщо в класі, звичайно, присутні геттери (чим менше функцій стосується внутрішніх елементів вашого класу, тим краще). Однак не додавайте додатковий геттер тільки для того, щоб перевантажити оператор через звичайну функцію замість дружньої! Якщо геттера немає за замовчуванням або він не використовується взагалі (в ньому немає необхідності), то тоді використовуйте перевантаження через дружні функції.
Правило: Використовуйте перевантаження операторів через звичайні функції, замість дружніх, якщо для цього не потрібне додавання додаткових функцій в клас.