Как предотвратить доступ к защищенным членам базового класса на втором уровне подкласса? - PullRequest
0 голосов
/ 26 февраля 2019

Пример, иллюстрирующий мою проблему:

class Base
{
protected:
    int x{ 0 };
};

class DerivedClass1 : public Base
{
};

class DerivedClass2 : public DerivedClass1
{
public:
    int getX() const
    {
        return x;
    }
};

int main()
{
    DerivedClass2 d2{};
    int x{ d2.getX() };
    return 0;
}

Я могу получить доступ к защищенному члену Base в классе DerivedClass2, хотя защищенные члены Base следует изменять только в DerivedClass1.Унаследовав переменную от Base до DerivedClass1, должен быть сформирован класс, которым DerivedClass2 не должен манипулировать.В C # это возможно с ключевым словом private protected, но как вы можете справиться с этим в C ++?

Ответы [ 3 ]

0 голосов
/ 26 февраля 2019

Каковы последствия защищенного?

Сама идея protected - предоставить всем производным классам доступ к таким членам.

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

Как избежать его недостатков?

Если вы хотите более сильную инкапсуляцию и ограниченный доступ, вам нужно перейти на private.Это гарантирует, что к внутреннему состоянию базового класса можно получить доступ только через открытый интерфейс.(Обратите внимание, что, хотя он обеспечивает ограничение истории, он сам по себе не гарантирует LSP).И следствием этого является то, что ни один производный класс не получает доступ.Не на первом выводе, а не позже.

Вам нужна личная защита?

То, что вы хотите, является своего рода промежуточным звеном: слабая инкапсуляция, но не слишком слабая.Этого не существует в C ++.И я не уверен, что это усилит ваш дизайн.

Но если вам нужно это ограничение в исключительных случаях, можно найти обходной путь, поиграв с поиском имени:

class DerivedClass1 : public Base
{
private:
    using Base::x; 
// In DerivedClass1 you can still use x.
};

// But it will fail to compile in Derived2

Демо онлайн

Но лично я бы не советовал идти по этому пути.Это подвержено ошибкам (вы можете забыть using в одном родном брате).Сообщения об ошибках компилятора могут вводить в заблуждение.И в любом случае, приватность дает более надежный дизайн.

0 голосов
/ 26 февраля 2019

Наследовать «частную» базу:

class DerivedClass1 : private Base
{

};

Редактировать: Предоставлять открытые или защищенные элементы в База через открытые или защищенные элементы в DerivedClass1 . DerivedClass1 затем получает полный контроль над тем, какие члены Base могут и не могут быть доступны для классов, унаследованных от DerivedClass1 .

Будет ли это хорошее решение, зависитпо сложности База .

0 голосов
/ 26 февраля 2019

Вы можете объявить элемент данных как private и использовать friend -declarations, чтобы явно указать, какие классы могут получить к нему доступ, хотя:

class Base
{
    friend class DerivedClass1;
private:
    int x = 0;
};

class DerivedClass1 : public Base
{
    void test() {
        cout << x;  // OK: DerivedClass1 is a friend of Base
    }
};

class DerivedClass2 : public DerivedClass1
{
public:
    int getX() const
    {
        return x;  // ERROR: x is a private member
    }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...