Скрытие класса C ++ в заголовке без использования безымянного пространства имен - PullRequest
4 голосов
/ 25 апреля 2011

Я пишу заголовок C ++, в котором я определяю

class A {
   // ...
};

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

Существует также класс B в том же заголовке, который имеет объект класса A в качестве члена:

class B {
public:
   // ...

private:
   A a_;
};

Как правильно скрывать класс А от внешнего мира?

Если я помещу определение A в безымянное пространство имен, компилятор выдаст предупреждение, поэтому я предполагаю, что из-за проблем с внутренней связью я должен сделать что-то еще.

Ответы [ 6 ]

8 голосов
/ 25 апреля 2011

Правильный путь в C ++ - это PIMPL идиома. Альтернативное решение - поместить класс, который вы хотите скрыть, во вложенное пространство имен, которое обычно называется detail. Но это не сделает его полностью закрытым, поскольку пользователи по-прежнему будут подвержены его зависимостям и смогут использовать его напрямую.

5 голосов
/ 25 апреля 2011

Вы можете сделать внутренний класс:

class B
{
  class A { /* ... */ };
  A a_;
}
1 голос
/ 25 апреля 2011

Безымянное пространство имен в любом случае бесполезно, так как оно защищает только несколько определений. То, что вы можете сделать, это либо использовать идиому pImpl, как упоминалось в других ответах, либо использовать пространство имен detail. Отлично работает для Boost:

namespace detail{
  class A{
    // ...
  };
}

class B{
public:
  // ...
private
  A a_;
};

Любой, кто возится с вещами в пространстве имен detail, напрашивается на неприятности. Или, может быть, еще больше запутать это

namespace _b_impl_detail{
  // ...
};

Любой, кто теперь касается чего-либо внутри, должен быть застрелен в ногу. :)

1 голос
/ 25 апреля 2011

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

В C ++ вы должны доверять программам, которые связываются с вашим библиотечным кодом, потому что у вас нет другого выбора. C ++ имеет ограниченные функции «контроля доступа», многие из которых можно обойти или злоупотребить, поэтому вам лучше относиться к своим клиентам API с уважением и укреплять доверие.

Если вы разрабатываете свой API так, чтобы его было легко и правильно использовать, а неумышленно неправильно использовать, то вы будете помогать своим клиентам, и вряд ли вы будете виноваты в том, что ваши клиенты злоупотребляют вашим интерфейсом.

1 голос
/ 25 апреля 2011

Если A - это деталь реализации B, вообще не помещайте ее определение в заголовок.Вместо этого:

class B {

   ...
   class A * myA;
};

и затем поместите определение A в файл реализации B (т.е. .cpp).

1 голос
/ 25 апреля 2011

Вместо class B, в котором содержится объект A, вместо этого удерживайте A* (или shared_ptr<A>, или unique_ptr<A> и т. Д.). Таким образом, class B требуется только предварительное объявление class A, а class A может быть полностью определено внутри исходного файла class B.

...