головные боли Пространства имен C++

Хорошо, этот вопрос развился немного, и я хочу попытаться запуститься с основных целей, для которых я стреляю:

  • Создайте код библиотеки тот устаревший язык C оберток, объекты в приобретении ресурса C++ являются инициализацией и также обеспечивают основную или лучшую гарантию исключения.
  • Позвольте клиентам этого кода использовать его очень естественным способом C++ w/o создающий много издержек к существующему коду для преобразования его для использования интерфейсных объектов C++ (т.е. автоматическое преобразование в соответствующие типы прежней версии, конструкторы, которые берут типы прежней версии, и т.д.),
  • Ограничьте влияние пространства имен кода библиотеки. Идеально, библиотека имела бы несколько подпространств имен, которые обеспечивают связанную функциональность, которые ограничивают объем и влияние использования описаний типа пространства имен X - как библиотеки повышения делают (т.е. использование пространств имен деталей, чтобы только ввести те символы, которые пользователь обоснованно хотел бы использовать и скрыть тех, которые являются деталями реализации; также ограничьте степень возможных новых значений к существующим символам, чтобы не удивлять неявные преобразования в рамках пользовательского кода),
  • Потребуйте, чтобы клиенты явно попросили те части библиотеки, чтобы они на самом деле хотели ввести в их кодовую базу. Это идет рука об руку с ограничением влияния включения заголовки библиотеки. Клиентский код должен иметь разумный уровень управления, по которому части библиотеки будут автоматически используемыми для определения имен, когда они компилируют свой код.
  • Моим собственным кодом библиотеки не придется пронизать, осуществляют рефакторинг - хрупкие конструкции кода. Это было бы идеально, если бы заголовки библиотеки не должны были постоянно объявлять частные определения типов, чтобы иметь доступ к остальной части того раздела библиотеки. Или другими словами: Я хочу, чтобы моя библиотека смогла быть записанным так интуитивно, как мои клиенты добираются до при использовании упомянутой библиотеки. Определение имен должно включать пространство имен, что библиотека определяется в в дополнение к любым другим, которые были явно "using'd".

Я часто сталкиваюсь с этим сценарием, и ищу лучший путь...

У меня есть класс, C в пространстве имен N. C имеет участника, Свободного. Это free's что-то, чем C управляет и позволяет C управлять новой вещью.

Существует несколько глобальных Бесплатных функций. Существует также несколько функций помощника в том же пространстве имен N как C, один из которых является помощником что free's вещь, управляемая C, названным свободным.

Таким образом, у нас есть что-то как:

namespace N {

void free(THING * thing);

class C
{
public:
  ... details omitted...
  free()
  { 
    free(m_thing); // <- how best to refer to N::free(THING&)
  }
}

} // namespace N

Я мог использовать N:: свободный (m_thing). Но это кажется неудачным мне. Там никакой путь не состоит в том, чтобы отослать к тому, что вне объема класса, но не разрешая абсолютное пространство имен (относительный шаг, мудрый объемом)?

Мне что, имея необходимость назвать N кажется:: свободный неприятно, так как Вы не имели бы к тому, если бы это было автономной функцией. И при этом Вам не было бы нужно к тому, если бы имя метода класса, оказалось, отличалось (например, расположило). Но потому что я использовал то же имя, я не могу получить доступ к нему, не имея необходимость указывать, какие суммы к полному пути - а не относительный путь - если Вы будете потворствовать мне аналогия.

Я ненавижу полные пути. Они делают перемещающиеся вещи в пространствах имен очень хрупкими, таким образом рефакторинг кода становится намного более ужасным. Плюс, правила того, как назвать вещи в телах функции, становятся более сложными с текущим подшипником (поскольку я понимаю их) - менее регулярный - стимулирование раскола между тем, что каждый ожидает и что каждый получает как программист.

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

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

namespace Toolbox {
  namespace Windows {

// deallocates the given PIDL
void Free(ITEMIDLIST ** ppidl);

class Pidl
{
public:
    // create empty
    Pidl() : m_pidl(NULL) { }

    // create a copy of a given PIDL
    explicit Pidl(const ITEMIDLIST * pidl);

    // create a PIDL from an IShellFolder
    explicit Pidl(IShellFolder * folder);

    ...

    // dispose of the underlying ITEMIDLIST* so we can be free to manage another...
    void Free();
};

Таким образом, ITEMIDLIST* прибывают из множества мест и уничтожаются с CoTaskMemFree (). Я мог представить Pidl как глобальное имя - а также все функции помощника в заголовке "Windows Shell.h", который является частью моей библиотеки панели инструментов.

Идеально, я сегментировал бы некоторые инструменты в моей библиотеке тем, чего они касаются - в этом случае, прежде всего, касается COM, программирующего в Windows. Я имею, выбрал Toolbox в качестве основного пространства имен для моего материала библиотек и в настоящее время думал, что я буду использовать Панель инструментов:: Windows для очень функций окон-y, классов, и т.д.

Но пространство имен C++ и правила определения имен, кажется, делают это очень трудным (следовательно этот вопрос). Это делает это очень неестественным для создания такой сегментации моего кода - с тех пор koenig сбои поиска (так как ITEMIDLIST не находится на моей Панели инструментов:: пространство имен Windows), и у меня нет способности переместить его туда! Ни если я. Язык должен быть достаточно выразительным, IMO, обоим позволяют, чтобы дополнительные библиотеки, такие как моя библиотека Toolbox расширились, другие люди кодируют, не имея необходимость вводить мои расширения в их пространство имен (который, в случае Win32 и общего подавляющего большинства кода, который существует сегодня, ГЛОБАЛЬНЫЙ NS - который является смыслом создания пространств имен во-первых: избегать глобальной давки NS / загрязнение / неоднозначность / программирующие неожиданности).

Так, я возвращаюсь вокруг к, Есть ли лучший способ сделать это: Расширьте существующие библиотеки кода, не загрязнение их NS с моими расширениями, но все еще допускает интуитивное и полезное определение имен, как можно было бы ожидать, был ли мой код в их NS, но явно представлен клиентом моего кода (т.е. Я не хочу вводить свой код волей-неволей, но только по явному запросу)?

Другая Мысль: Возможно, что удовлетворило бы, мой выше критериев был бы то, если бы у меня было следующее:

using namespace X {
  code here...
}

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

5
задан Mordachai 15 December 2009 в 15:25
поделиться

5 ответов

Я не вижу, чтобы избежать необходимости указывать здесь namespace-scope free () , но следует отметить, что это не то же самое, что «абсолютный путь». Во-первых, если у вас есть вложенные пространства имен, вам нужно обратиться только к самому внутреннему:

namespace N1 {
  namespace N2 {
    namespace N3 {
      void free(THING * thing);

      class C {
      public:
        free() {
          N3::free(m_Thing); // no need to do N1::N2::
        }
      };
    }
  }
}

[EDIT] в ответ на отредактированный вопрос. Опять же, я не вижу никакого способа сделать это в том сценарии, который вы описываете. Однако это не кажется идиоматическим подходом C ++ - более распространенный способ сделать то же самое - предоставить собственный класс-оболочку для ITEMIDLIST , который управляет всеми выделениями в стиле RAII и предоставляет исходный дескриптор (например, с помощью операторов преобразования а-ля ATL или явной функции-члена, такой как c_str () , если вам нужна дополнительная безопасность). Это полностью устранит необходимость в вашем бесплатном , и для любой другой бесплатной функции, которая может вам понадобиться, поскольку вы контролируете тип оболочки и пространство имен, в котором она находится, вы можете использовать ADL как обычно.

[РЕДАКТИРОВАТЬ №2] . Эта часть вопроса:

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

Разве это не то, что вы помещаете в пространство имен, и ваш клиент, записывающий с использованием пространства имен ... , достигнет?

6
ответ дан 13 December 2019 в 19:28
поделиться

Мне кажется, что здесь есть проблема дизайна.

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

Я стараюсь не уточнять имена внутри метода, но здесь, конечно, вы рискуете of сокрытие , где MyClass :: free скрывает метод N :: free , который никогда не участвует в поиске ... попытался выяснить разрешение области здесь, но мне не удалось найти точный отрывок.

Для обмена я просто использую:

class MyClass
{
  void swap(MyClass& rhs)
  {
    using std::swap;         // Because int, etc... are not in std
    swap(m_foo, rhs.m_foo);
    swap(m_bar, rhs.m_bar);
  }
};

inline void swap(MyClass& lhs, MyClass& rhs) { lhs.swap(rhs); }

Поэтому я удостоверяюсь, что правильный метод будет включен в поиск, и избегаю использования «глобального» метода, если таковой имеется.

0
ответ дан 13 December 2019 в 19:28
поделиться

Юу мог написать :: free (m_thing); . Это вызовет глобальную функцию free () . Однако если у вас есть другая функция free () за пределами пространства имен N, у вас возникнут проблемы. Либо измените имена некоторых из ваших функций, либо используйте имя функции с явным пространством имен.

0
ответ дан 13 December 2019 в 19:28
поделиться

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

0
ответ дан 13 December 2019 в 19:28
поделиться

У вас есть два варианта:

  1. Полное определение имени функции.
  2. Пусть Поиск Кёнига выполнит задание (если THING принадлежит пространству имен N ).

Я бы выбрал первую с таким популярным именем функции, как free .

Альтернативный вариант - использовать m_thing-> Release () или что-то в этом роде.

5
ответ дан 13 December 2019 в 19:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: