Перейти к основному содержимому

О доступе к защищенным элементам базового класса в производном классе

· 2 мин. чтения
Дмитрий Аладин
Преподаватель

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

Иллюстрирующий пример

Исходный пример:

#include <iostream>
using namespace std;

class Base {
protected:
int protected_value_;

public:
Base() : protected_value_{0} {}
Base(int t_value) : protected_value_{t_value} {}
virtual ~Base() = 0;
};

Base::~Base() {}

class Child : public Base {
public:
Child() : Base() {}
Child(int t_value) : Base(t_value) {}
int sum(Base* children, size_t count) {
int result = 0;
for (size_t i = 0; i < count; i++) {
// Ошибка компиляции:
// не удается получить доступ к защищенному члену "Base::protected_value_"
// (объявлено в строке 6) с помощью указателя "Base" на объект
result += children[0].protected_value_;
}
return result;
}
~Child() {}
};

Обратите внимание на строчку result += children[0].protected_value_;. На данной строке происходит попытка получить доступ к защищенному полю protected_value_ базового класса Base из производного Child. Компилятор на этой строчке выдаст ошибку доступа к защищенному полю.

Объяснение проблемы

Для объяснения причины возникновения данной ошибки, обратим внимание на то, что означает использование protected в классе:

Член (либо элемент данных, либо функция-член), объявленный в protected разделе класса, может быть доступен только функциям-членам и друзьям этого класса, а также функциям-членам и друзьям производных классов.

Иными словами, protected доступ к элементам возможен:

  • через this указатель;
  • к защищенным элементам того же типа, даже если они объявлены в base;
  • из дружественных классов, функций.

Производный класс не может обращаться к защищенным элементам экземпляров базового (родительского) класса!

В вашем случае Child класс может обращаться только к защищенному элементу protected_value_ экземпляров Child, но не к защищенному элементу protected_value_ экземпляров Base.

Решение проблемы

Чтобы решить эту проблему, вы можете явно указать дружественность производного класса к базовому классу, не нарушая инкапсуляцию:

#include <iostream>
using namespace std;

class Child;

class Base {
protected:
int protected_value_;

public:
Base() : protected_value_{0} {}
Base(int t_value) : protected_value_{t_value} {}
virtual ~Base() = 0;
friend Child;
};

Base::~Base() {}

class Child : public Base {
public:
Child() : Base() {}
Child(int t_value) : Base(t_value) {}
int sum(Base* children, size_t count) {
int result = 0;
for (size_t i = 0; i < count; i++) {
// Всё ок! Работает дружественность.
result += children[0].protected_value_;
}
return result;
}
~Child() {}
};