Методы инкапсуляции C ++
-
11-09-2019 - |
Вопрос
Я пытаюсь правильно инкапсулировать класс A, с которым должен работать только класс B.
Однако я хочу наследовать от класса B.
Иметь друга Б не работает - дружба не передается по наследству.
Каков общепринятый способ достичь того, чего я хочу, или я совершаю ошибку?
Чтобы придать вам немного больше красочности, класс A представляет состояние сложной системы.Он должен быть изменен только с помощью B, которые являются действиями, которые могут быть применены для изменения состояния класса A.
Решение
Я предполагаю, что вы хотите разрешить потомкам B прямой доступ к A?Если A и B тесно связаны, вы можете сделать A защищенным определением класса внутри самого B, вместо того чтобы быть независимым определением.Например,Дж.
class B
{
protected:
class A
{
};
};
Другая идея состоит в том, чтобы создать защищенные методы на B, которые делегируют свои действия A.Например,Дж.
class A
{
friend class B;
private:
void DoSomething();
};
class B
{
protected:
void DoSomething(A& a) { a.DoSomething(); }
};
Другие советы
Похоже, вам, возможно, придется сделать редизайн;ваш класс A представляет состояние, но ваш класс B представляет собой набор действий.Здесь есть какая-то связь, но это не отношения наследования.Я бы предложил композицию;насколько я могу судить, вы хотите больше отношений с HASA, чем с ISA.
Если я вас правильно понял, вы хотите иметь Б и это производные чтобы иметь доступ к внутренней реализации класса А, да?
К сожалению, в C ++ нет концепции "внутренних" уровней защиты, которыми обладают такие языки, как C # и Java.
Вы можете рассмотреть возможность использования парадигма частной реализации (pimpl) - также известные как непрозрачные указатели, для раскрытия функциональности в вашей системе с использованием уровней публичного доступа, которые пользователи A и B не увидят.
Сохраняя все как есть, самое простое, что можно сделать, это добавить защищенные методы в B, которые предоставляют доступ к эквивалентной функции A, которая ему понадобится.Это открывает инкапсуляцию только для подклассов B.
Самый простой способ сделать это - просто заставить B содержать A:
класс B { защищенный:А а_;};
Затем вы можете написать класс C, который наследуется от B и способен манипулировать A.Если C не должен иметь возможности выполнять произвольные действия с A, то сделайте A закрытым в B и предоставьте защищенные методы в B, которые C может использовать для выполнения одобренных действий с A, вот так:
класс B { частный:А а_;защищенный:аннулировать досометингтоа();};
Сдерживание - это правильный путь (класс B содержит закрытый элемент типа A), если B не нуждается в переопределении некоторых виртуальных объектов в A, и в этом случае частное наследование это самая близкая вещь.
Я не могу понять, почему ты хочешь получить наследство.Делайте все в частном порядке и по-дружески.Тогда B имеет элемент A, которым он может свободно манипулировать.
То, как вы это описываете, больше похоже на композицию, а не на наследование.Например.
class ComplexMachine {
public:
setState(int state);
};
class Operator {
public:
Operator(ComplexMachine & m) :_m(m) {};
void drive() { _m->setState(1); }
void turn() { _m->setState(2); }
void stop() { _m->setState(0); }
private:
ComplexMachine _m;
};
class SmoothOperator : public Operator { }
Работа с фрагментами информации, которые вы предоставили:
Класс B должен отвечать за сохранение инвариантов класса A, а класс B должен быть единственным способом манипулирования A.Любому производному от клиента классу или вызывающей стороне не обязательно знать, что A существует.
(Судя по дизайну POV, там даже нет потребность для того, чтобы A существовало, но я столкнулся с достаточным количеством практических причин для такого разделения, так что я не буду держать на вас зла за это ;))
Для этого может потребоваться написать много шаблонного кода или какие-то хитрости с интерфейсом.например ,если клиенту должно быть разрешено использовать класс A для запроса информации, но не для ее изменения, B мог бы передать const & агрегированному A.С помощью компилятора, поддерживающего __declspec(свойство) или аналогичное, синтаксическая сложность может быть облегчена.
Если вы хотите быть уверены, что только B работает с A, сделайте экземпляр A частным и предоставьте защищенный интерфейс от B его потомкам.
class A
{
public:
void foo() {}
};
class B
{
private:
A a;
protected:
void CallAFoo() { a.foo() };
};
class C : public B
{
void goo() { CallAFoo(); }
};
Насколько я понял из вашего вопроса, вам понадобятся некоторые полиморфизм.Вам нужен абстрактный классы A и B наследуют класс A.Кроме того, защищенный ключевое слово позволяет классам, которые наследуют, иметь доступ к определенной информации и в то же время запрещать доступ ко всему остальному.Вот небольшой пример:
// dynamic allocation and polymorphism
#include <iostream>
using namespace std;
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
void printarea (void)
{ cout << this->area() << endl; }
};
class CRectangle: public CPolygon {
public:
int area (void)
{ return (width * height); }
};
class CTriangle: public CPolygon {
public:
int area (void)
{ return (width * height / 2); }
};
int main () {
CPolygon * ppoly1 = new CRectangle;
CPolygon * ppoly2 = new CTriangle;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly1->printarea();
ppoly2->printarea();
delete ppoly1;
delete ppoly2;
return 0;
}
Код взят из cplusplus.com (также содержит информацию о полиморфизме и абстрактных классах).