Вопрос

Я пытаюсь правильно инкапсулировать класс 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 (также содержит информацию о полиморфизме и абстрактных классах).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top