Оба класса и пространства имен?
Этот вопрос касается шаблона, который, как я вижу, я использую все больше и больше: наличие как класса, так и пространства имен для связанных понятий. Я думаю, что это мотивировано главным образом артефактами языка С++, но не полностью.
Я полагаю, что вопрос верхнего уровня: это хорошая идея? Имея как класс, так и пространство имен для связанных понятий?
Вопрос нижнего уровня:
Каков наилучший способ сделать это?
Класс, вложенный в пространство имен?:
namespace Foo_Namespace {
class Foo_Class {
...
};
}
Или отдельный, одноранговый, класс и пространство имен?:
class Foo_Class {
...
};
namespace Foo_Namespace {
// non-class free functions, etc.
}
Я должен признать, что я склоняюсь к вложению класса в пространство имен. Хотя это приводит к уродливым именам. Но даже если я это сделаю, какие соглашения об именах следует использовать:
Слишком длинное, что приводит к действительно уродливым именам Foo_Namespace:: Foo_Class
namespace Foo_Namespace {
class Foo_Class {
...
};
}
Нет необходимости использовать суффиксы или индикаторы в имени:
namespace Foo {
class Foo {
...
};
}
Но тогда я нахожу себя неуверенным, когда смотрю на Foo:: bar(), если это бесплатная функциональная панель в пространстве имен:: Foo, т.е.:: Foo:: bar() или функция-член в классе Foo в пространстве имен:: Foo:: Foo:: bar().
И имена вроде:: Foo:: Foo:: bar по-прежнему не являются, umm, nice.
В настоящее время я делаю
Нет необходимости использовать суффиксы или индикаторы в имени:
namespace Foo_ns {
class Foo {
...
};
}
главным образом потому, что я обычно сначала создаю класс, а потом понимаю, что пространство имен будет приятным.
Интересно, если я должен возродить соглашение об именах, которое я не использовал в годах: _c для класса, _ns для пространств имен:
namespace Foo_ns {
class Foo_c {
...
};
}
Детали:
Я не буду повторять то, что я сказал выше, но я добавлю немного больше.
Самая практическая причина, по которой я знаю, использовать пространство имен в дополнение к классу, заключается в том, что вам разрешено отправлять декларации свободных функций в пространстве имен, но вам не разрешено делать пересылку объявлений некоторых методов класса, То есть с классом вы должны объявить все или ничего. В то время как со свободными функциями вообще и свободными функциями в пространствах имен, в частности, вы можете объявить это по частям. Части могут быть объявлены в разных файлах заголовков. Вместо #, включая массивную библиотеку только для заголовка для массивного класса, вы можете использовать форвардные объявления только для одной или двух функций. Etc.
(см., например, http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Forward_Declarations, хотя Google беззаботно отказывается от форвардных деклараций, а не включает заголовок.)
Другая причина заключается в том, что пространство имен позволяет сохранить класс в целом.
Самое большое преимущество для класса состоит в том, что класс может быть передан шаблону, тогда как пространство имен не может быть.
Я предпочитаю, чтобы класс, вложенный в пространство имен, Foo_ns/Foo_ns:: Foo_c, вместо того, чтобы иметь их как peer Foo_ns/Foo_c, потому что часто классу нужны вспомогательные классы, например. Foo_ns/Foo_ns:: Foo_c/Foo_ns:: Foo_Helper_c. Если класс и пространство имен являются одноранговыми, кажется странным иметь Foo_ns/Foo_c, но Foo_ns:: Foo_Helper_c.
Мне нравятся пространства имен, потому что я согласен с Андреем Александресю: http://laser.inf.ethz.ch/2012/slides/Alexandrescu/1-C++%20course%20parts%201%20and%202.pdf
Class methods vs. free functions
• Conventional wisdom: methods are cool, free functions are so 1960s
• Yet:
◦ Free functions improve encapsulation over methods
◦ Free functions may be more general
◦ Free functions decouple better
◦ Free functions support conversions on their left-hand argument
Surprising fact #2
Making a function a method should be
your last, not first, choice
(c) 2012– Andrei Alexandrescu. 32 / 59
Лучше создавать свободные функции, чем методы в классах.
Но иногда нужно просто использовать классы - например, для шаблонов.
Соглашение об именах мудрый
Я использовал Foo_ns/Foo_ns:: Foo_c в прошлом
Я использую Foo_ns/Foo_ns:: Foo now
(Кстати, я предпочитаю использовать Class_Names_With_Underscores_and_Initial_Caps, а не CamelCase.)
Если это имеет смысл, я могу исключить суффикс _ns в пространстве имен - например. где пространство имен и класс не должны иметь одинаковое имя.
Мне не нравится, что они имеют одно и то же имя. Рассмотрим конструктор для класса Foo внутри пространства имен foo:
:: Foo:: Foo:: Foo() против :: Foo_ns:: Foo:: Foo()
Последнее не намного лучше, но немного запутаннее.
Я думаю, что я обычно создаю класс сам по себе, не вложив его в пространство имен. Фактически, я, вероятно, добавляю несколько статических методов, прежде чем я пойму, что класс, вложенный в пространство имен, будет лучше. На этом этапе это может быть болью для рефакторинга, и иногда я создаю функции пересылки, которые переходят от статического метода класса к свободной функции в пространстве имен или наоборот. Это заставляет меня сожалеть о боте, чтобы перейти к классу с пространством имен прямо с шага 1.
Заключение
Мой текущий BKM - Foo_ns/Foo_ns:: Foo, т.е.
namespace Foo_ns {
class Foo {
...
};
}
Буду признателен за любые предложения, любые улучшения.
Или я просто сломался для этого?