TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #1011 4.4K
​​Доступ к приватным членам. Други-классы.
#новичкам

Ключевое слово friend может использоваться также, чтобы дать доступ ко всем непубличным членам одного класса другому классу. Ну или точнее - сразу всем его методам.

class Matrix {
private:
int data[10][10];
public:
friend class MatrixAnalyzer;
};

class MatrixAnalyzer {
public:
int sum(const Matrix& m) {
int sum = 0;
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
sum += m.data[i][j]; // Access private data
return sum;
}
};


Внутри класса Matrix делаем объявление класса MatrixAnalyzer и говорим, что он нам друг. Тогда в реализации MatrixAnalyzer мы сможем пользоваться приватными членами Matrix.

С друзьями классами ситуация еще серьезнее. Вы даете доступ к непубличным членам буквально каждому методу другого класса. И все эти методы могут вертеть все поля объекта на всех потенциальных вертелах. Это реально бывает где-то нужно?

Для любой гаечки в С++ найдется свое применение. И для другов-классов тоже:

1️⃣ У вас есть класс, который содержит в своем публичном скоупе еще один класс. Но у этого вложенного класса есть какие-то приватные члены, к которым хотелось бы получить доступ.

Например, есть класс контейнера-связного списка. В него вложен публичный класс итератора и приватный класс ноды.
template <typename T>
class LinkedList {
private:
struct Node {
T data;
Node *next;
public:
Node(const T &value, Node *n = nullptr) : data(value), next(n) {}
};
Node *head = nullptr;
public:
class Iterator {
private:
Node *current;
Iterator(Node *node) : current(node) {}
friend class LinkedList<T>;
public:
// ...
};

// ...
};


Мы не хотим, чтобы какой-то левый код мог создавать итератор, поэтому пометили его конструктор приватным. Но LinkedList-то должен уметь создавать итератор. Для этого мы и помечает LinkedList другом итератора, чтобы разрешить ему вызывать приватный конструктор.

2️⃣ Юнит-тестирование. Обычно конечно тестируют только публичный интерфейс класса и стараются покрыть все пути исполнения и кейсы использования, чтобы абсолютно вся логика, включая приватные методы, была протестирована. Это называется black-box тестирование.

Но иногда очень хочется отдельно протестировать конкретные приватные методы и проверить значения приватных полей. Если ваши приватные методы реализуют какие-то логически полные части общего алгоритма, то удобно явно в коде их и тестировать, чтобы ни один баг не проскочил. Это называется white-box тестирование.

И вот для белого ящика нужно пометить класс тестов другом тестируемого класса.

class Database {
private:
bool validateConnectionString(const std::string& connStr) {
// Very complicated logic
return true;
}
friend class DatabaseTest; // HERE
};

class DatabaseTest {
public:
static bool testValidation() {
Database db;
return db.validateConnectionString("valid string");
}
};


А какой вид тестирования предпочитаете вы? Почему?

Во время подготовки к этому посту нашел еще один интересный кейс применения, но он заслуживает отдельного поста.

Have friends. Stay cool.

#cppcore
  • ❤ 24
  • 😁 13
  • 👍 9
  • 🔥 3
  • 🤯 1
More from @grokaemcpp
  1. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  2. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  3. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  4. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  5. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  6. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →