Наследование и скрытие родительских атрибутов

Разумно ли делать что-то подобное?

Примечание: это минимальный рабочий пример

class A {
public:
int getX() { return x; }
protected:
int x;
virtual void setX(int newX) = 0;
};

// Children can modify X
class Can_Modify_X : public A {
protected:
void setX(int newX) { x = newX; }
private:
using A::x;
};

// Children can't modify X
class Can_Not_Modify_X : public A {
private:
void setX(int newX) { }
using A::x;
};

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

Два класса должны иметь общего родителя (даже если он является одним из них) и не должны иметь возможности изменять x непосредственно.

БОНУС: может кто-нибудь указать мне где-то, определяя точное поведение using в этом случае? Я пытался погуглить, но без особого успеха.

0

Решение

Я знаю, что я не могу просто скрыть функцию, потому что это нарушит принцип Лискова.

Точно такая же концепция применяется к членам данных.

Предположим, у вас есть указатель (или ссылка) на экземпляр Can_Modify_X или же Can_Not_Modify_X, Вы не можете получить доступ или изменить данные члена x через эту ссылку. Если вы отклоните указатель этого производного класса на указатель на класс A вы вдруг можете изменить данные члена x, Делая x частный, вы нарушаете принцип подстановки Лискова. Неважно, x является членом данных, функцией-членом или определением типа. Ты нарушаешь подмену Лискова, чисто и просто.

Производные классы не должны скрывать возможности, предоставляемые родительским классом.

1

Другие решения

Что вы ожидаете от следующего кода?

A * a = new Can_Not_Modify_X();
a->setX(10);
0

Это субъективный вопрос, поэтому мой ответ будет соответственно субъективным.

Я собираюсь сказать нет, это не разумно. protected Атрибуты позволяют дочерним классам очень легко случайно изменять состояние и нарушать инварианты, поэтому я предлагаю полностью их избегать. Тогда ваш родительский класс будет поддерживать x через общедоступный или защищенный интерфейс (надеюсь, с помощью значимого набора методов, а не просто мутаторов).

Тогда вам не нужно менять доступность в дочерних элементах, поскольку ваш интерфейс уже контролирует доступ соответствующим образом.

Мало того, что изменение доступности членов или методов нарушает принцип наименьшего удивления и, скорее всего, вызовет проблемы у ваших будущих сопровождающих.

0
По вопросам рекламы [email protected]