Я понимаю, что библиотека C++ должна использовать пространство имен для предотвращения коллизий имени, но так как я уже имею к:
#include
корректный заголовок (или вперед объявляют классы, которые я намереваюсь использовать),Не делайте эти два параметра выводят ту же информацию, переданную пространством имен. Используя пространство имен теперь представляет третий параметр - полностью определенное имя. Если реализация изменений библиотеки, существует теперь три потенциальных вещи, я должен измениться. Это не, по определению увеличение связи между кодом библиотеки и моим кодом?
Например, взгляд на Xerces-C: Это определяет чисто-виртуальный названный интерфейс Parser
в пространстве имен XERCES_CPP_NAMESPACE
. Я могу использовать Parser
интерфейс в моем коде включением соответствующего заголовочного файла и затем любым импортом пространства имен using namespace XERCES_CPP_NAMESPACE
или снабжение предисловием объявлений/определений с XERCES_CPP_NAMESPACE::
.
Поскольку код развивается, возможно, существует потребность отбросить Xerces в пользу другого синтаксического анализатора. Я частично "защищен" от изменения в реализации библиотеки чисто-виртуальным интерфейсом (еще больше, если я использую фабрику для построения моего Синтаксического анализатора), но как только я переключаюсь от Xerces до чего-то еще, я должен прочесать свой код и изменить все мой using namespace XERCES_CPP_NAMESPACE
и XERCES_CPP_NAMESPACE::Parser
код.
Я столкнулся с этим недавно, когда я осуществил рефакторинг существующий проект C++ разделить некоторую существующую полезную функциональность на библиотеку:
foo.h
class Useful; // Forward Declaration
class Foo
{
public:
Foo(const Useful& u);
...snip...
}
foo.cpp
#include "foo.h"
#include "useful.h" // Useful Library
Foo::Foo(const Useful& u)
{
... snip ...
}
В основном из незнания (и частично из лени) в то время, вся функциональность useful.lib
был помещен в глобальное пространство имен.
Как содержание useful.lib
вырос (и больше клиентов начало использовать функциональность), было решено переместить весь код от useful.lib
в его собственное названное пространство имен "useful"
.
Клиент .cpp
файлы было легко зафиксировать, просто добавить a using namespace useful
;
foo.cpp
#include "foo.h"
#include "useful.h" // Useful Library
using namespace useful;
Foo::Foo(const Useful& u)
{
... snip ...
}
Но .h
файлы были действительно трудоемкими. Вместо того, чтобы загрязнить глобальное пространство имен путем помещения using namespace useful;
в заголовочных файлах я перенес существующие предописания в пространство имен:
foo.h
namespace useful {
class Useful; // Forward Declaration
}
class Foo
{
public:
Foo(const useful::Useful& u);
...snip...
}
Были десятки (и десятки) файлов, и это закончило тем, что было сильной болью! Это не должно было быть настолько трудно. Очевидно я сделал что-то не так с любым дизайн и/или реализация.
Хотя я знаю, что код библиотеки должен быть в его собственном пространстве имен, был бы он быть выгодным для кода библиотеки остаться в глобальном пространстве имен и вместо этого попытаться справиться #includes
?
Мне кажется, что ваша проблема в первую очередь связана с тем, как вы (ab) используете пространства имен, а не с самими этими пространствами.
Звучит так, как будто ты бросаешь много минимально связанных "вещей" в одно пространство имен, в основном (когда ты к этому приступаешь), потому что они случайно были разработаны одним и тем же человеком. По крайней мере, IMO, пространство имён должно отражать логическую организацию кода, а не просто случайность, что кучу утилит написал один и тот же человек.
Название пространства имен обычно должно быть достаточно длинным и описательным, чтобы предотвратить любую возможность столкновения, кроме самой отдаленной. Например, я обычно включаю свое имя, написанную дату и краткое описание функциональности пространства имен.
Большинство клиентского кода не нуждается (и часто не должно) использовать настоящее имя пространства имен напрямую. Вместо этого он должен определить псевдоним пространства имен, и только псевдоним должен использоваться в большинстве кода.
Складывая точки два и три вместе, мы можем получить в итоге что-то вроде кода:
#include "jdate.h"
namespace dt = Jerry_Coffin_Julian_Date_Dec_21_1999;
int main() {
dt::Date date;
std::cout << "Please enter a date: " << std::flush;
std::cin>>date;
dt::Julian jdate(date);
std::cout << date << " is "
<< jdate << " days after "
<< dt::Julian::base_date()
<< std::endl;
return 0;
}
Это устраняет (или, по крайней мере, резко уменьшает) связь между клиентским кодом и конкретной реализацией классов дата/время. Например, если бы я хотел переопределить одни и те же классы даты/времени, я мог бы поместить их в другое пространство имен и переключаться между ними, просто меняя псевдоним и перекомпилируя.
На самом деле, я использовал это иногда как своего рода механизм полиморфизма времени компиляции. Например, я написал пару версий небольшого класса "display", один из которых отображает вывод в списке Windows, а другой - через iostreams. Затем код использует псевдоним вроде:
#ifdef WINDOWED
namespace display = Windowed_Display
#else
namespace display = Console_Display
#endif
Остальной код просто использует display::whatever
, так что пока оба пространства имен реализуют весь интерфейс, я могу использовать любой из них, вообще не меняя остальной код, и без каких-либо накладных расходов на выполнение от использования указателя/ссылки на базовый класс с виртуальными функциями для реализации.
Я хотел бы расширить второй абзац Дэвида Родригеса - ответ dribeas (одобрено):
Чтобы упростить пересылку, вы могли бы написать прямой заголовок (в STL есть пара, вы, конечно найдите его в библиотеках), например, полезныйfwd.h, который только определяет интерфейс библиотеки (или реализует классы или что вам нужно). Но это не имеет отношения к сцеплению.
Думаю, это указывает на суть вашей проблемы. Пространства имен здесь - отвлекающий маневр, вас укусила недооценка необходимости содержать синтаксические зависимости.
Я могу понять вашу "лень": это неправильно для сверхинженера ( enterprise HelloWorld.java), но если вы вначале будете сдерживать свой код (что не обязательно ошибочен), и код окажется успешным, успех поднимет его выше своей лиги. уловка состоит в том, чтобы уловить подходящий момент для переключения (или применить с первого момента возникновения необходимости) технику, которая устраняет зуд с прямой совместимостью .
Искрометные предварительные заявления по проекту - это просто напоминание о втором и последующих раундах. Вам не обязательно быть программистом на C ++, чтобы прочитать совет «не объявляйте стандартные потоки вперед, используйте вместо них
» (хотя это было актуально несколько лет; 1999 - эпоха VC6, определенно). Вы можете услышать множество болезненных воплей от программистов, которые не прислушались к совету, если немного задержаться.
Я могу понять побуждение держать его в тени, но вы должны признать, что #include <полезныйfwd.h>
не больше боли, чем класс Полезные
и шкалы . Это простое делегирование избавит вас от N-1
изменений с класса Полезный
на класс Полезный :: Полезный
.
Конечно, это не поможет вам во всех случаях использования клиентского кода. Простая помощь: фактически, если вы используете библиотеку в большом приложении, вы должны заключить прямые заголовки, поставляемые с библиотекой, в заголовки для конкретного приложения. Важность этого растет с увеличением объема зависимости и изменчивости библиотеки.
src / libuseful / полезныйfwd.h
#ifndef GUARD
#define GUARD
namespace useful {
class Useful;
} // namespace useful
#endif
src / myapp / myapp-полезныйfwd.h
#ifndef GUARD
#define GUARD
#include <usefulfwd.h>
using useful::Useful;
#endif
В основном, это вопрос сохранения кода DRY . Возможно, вам не понравятся броские TLA, но этот описывает действительно основной принцип программирования.
Что ж, правда в том, что нет способа легко избежать запутывания кода на C ++. Однако использование глобального пространства имен - худшая идея, потому что тогда у вас не будет возможности выбирать между реализациями. Вы получаете Object вместо Object. Это нормально работает внутри компании, потому что вы можете редактировать исходный код по ходу дела, но если кто-то отправляет такой код клиенту, им не следует ожидать, что он будет долгим.
После того, как вы используете оператор using, вы также можете оказаться в global, но может быть удобно использовать его в файлах cpp. Поэтому я бы сказал, что у вас должно быть все в пространстве имен, но для внутреннего использования все должно быть одним и тем же пространством имен. Таким образом, другие люди могут использовать ваш код без сбоев.
Пространство имен не имеет ничего общего со связью. Такая же связь существует независимо от того, называете ли вы его полезным :: UsefulClass
или просто UsefulClass
. Теперь тот факт, что вам нужно было выполнить всю эту работу по рефакторингу, лишь говорит вам, в какой степени ваш код зависит от вашей библиотеки.
Чтобы упростить пересылку, вы могли бы написать заголовок forward
(есть пара в STL, вы наверняка можете найти его в библиотеках), например полезныйfwd.h
, который только пересылает определили интерфейс библиотеки (или реализующие классы, или что вам нужно). Но это не имеет отношения к сцеплению.
Тем не менее, связь и пространства имен просто не связаны. Роза будет так же сладко пахнуть под любым другим именем, и ваши классы так же связаны в любом другом пространстве имен.
(a) интерфейсы/классы/функции из библиотеки
Не больше, чем у вас уже есть. Использование пространства имён
-ed компонентов библиотеки поможет вам избавиться от загрязнения пространства имён.
(b) подробности реализации, выведенные из пространства имён?
Почему? Все, что вам нужно включить - это заголовок useful.h
. Реализация должна быть скрыта (и находиться в useful.cpp
и, вероятно, в форме динамической библиотеки).
Вы можете выборочно включить только те классы, которые вам нужны из useful.h
, имея с помощью полезных::Useful
деклараций.
Если у вас есть несколько реализаций вашей «полезной» библиотеки, то разве не одинаково вероятно (если не под вашим контролем), что они будут использовать одно и то же пространство имен, будь то глобальное пространство имен или полезное пространство имен?
Иными словами, использование именованного пространства имен в сравнении с глобальным пространством имен не имеет ничего общего с тем, как вы «связаны» с библиотекой/реализацией.
Любая согласованная стратегия эволюции библиотеки должна поддерживать одно и то же пространство имен для API. Реализация может использовать различные пространства имен, скрытые от вас, и они могут изменяться в различных реализациях. Не уверен, что это то, что вы имеете в виду под «деталями реализации, выведенными пространством имен».
-121--3783522-Я делаю следующее...
Нажмите правую кнопку мыши на панели TaskBar в инструменте для разработчиков de IE 8, чтобы выбрать перемещение.
Затем попытайтесь перемещаться с помощью мыши или с помощью стрелок
-121--840152-Нет, вы не увеличиваете муфту. Как говорили другие - я не вижу, как использование пространства имен утекает реализация
потребитель может выбрать, чтобы сделать
using useful;
using useful::Foo;
useful::Foo = new useful::Foo();
мой голос всегда за последний - его наименее загрязняющий
ТО первый следует решительно отказаться (путем расстрела)
Если у Вас несколько реализаций Вашей "полезной" библиотеки, то не одинаково ли вероятно (если не под Вашим контролем), что они будут использовать одно и то же пространство имён, будь то глобальное пространство имён глобальное или пространство имён полезное ?
Другими словами, использование пространства имён в сравнении с глобальным пространством имён не имеет никакого отношения к тому, насколько Вы "связаны" с библиотекой/реализации.
Любая стратегия развития когерентной библиотеки должна поддерживать одно и то же пространство имён для API. Реализация может использовать различные скрытые от вас пространства имен, которые могут меняться в различных реализациях. Не уверен, что это то, что вы подразумеваете под "деталями реализации, выведенными из пространства имен"
.