Иногда у меня есть классы с закрытыми статическими элементами данных. В настоящее время я обсуждаю, следует ли заменить их статическими переменными в безымянном пространстве имен в файле реализации. Помимо невозможности использовать эти переменные во встроенных методах, есть ли другие недостатки? Преимущество, которое я вижу, заключается в том, что оно полностью скрывает их от пользователей класса.
статические данные класса и анонимные пространства имен в C++
Ответы (6)
Я не уверен, что польза стоит влияния на читабельность. Обычно я считаю что-то личное «достаточно скрытым».
1) Есть недостаток в виде добавленного ограничения на бинарную организацию. В презентации на конференции C++ в 1990-х годах Уолтер Брайт сообщил о значительном повышении производительности за счет организации своего кода таким образом, чтобы функции, вызывающие друг друга, находились в одной единице компиляции. Например, если во время выполнения Class1::method1 сделал гораздо больше вызовов методов Class2, чем других Class1::methods, определение Class1::method1 в class2.cpp означало, что Class1::method1 будет на той же кодовой странице, что и методы. он звонил и, следовательно, с меньшей вероятностью будет задержан из-за ошибки страницы. Этот вид рефакторинга легче выполнить со статикой класса, чем со статикой файла.
2) Одним из аргументов против введения ключевого слова пространства имен было «То же самое можно сделать с классом», и вы увидите, что класс и структура используются в качестве пространства имен бедняка в источниках из эпоха до пространства имен. Убедительным контраргументом было то, что пространства имен открываются повторно, и любая функция в любом месте может сделать себя частью пространства имен или получить доступ к чужому пространству имен, тогда были вещи, которые вы могли делать с пространством имен, но не могли не делать с классом. Это имеет отношение к вашему вопросу, потому что предполагает, что языковой комитет думал о области пространства имен так же, как о области класса; это снижает вероятность того, что в использовании анонимного пространства имен вместо статического класса есть какая-то тонкая лингвистическая ловушка.
Я не согласен с другими ответами. Держите как можно больше вне определения класса.
В Эффективное C++ Скотта Мейерса, третье издание, он рекомендует предпочитая недружественные функции методам класса. Таким образом, определение класса становится как можно меньше, доступ к частным данным осуществляется в минимально возможном количестве мест (инкапсулируется).
Следование этому принципу далее приводит к идиоме pimpl. Однако необходим баланс. Убедитесь, что ваш код ремонтопригоден. Слепое следование этому правилу привело бы к тому, что вы сделали бы все ваши приватные файлы методов локальными и просто передавали бы необходимые элементы в качестве параметров. Это улучшит инкапсуляцию, но ухудшит ремонтопригодность.
Все это говорит о том, что файловые локальные объекты очень сложно тестировать. С помощью умного взлома вы можете получить доступ к закрытым членам во время модульных тестов. Доступ к локальным объектам файла немного сложнее задействован.
Он не только скрывает их от пользователей класса, он скрывает их от вас! Если эти переменные являются частью класса, они должны быть каким-то образом связаны с классом.
В зависимости от того, что вы собираетесь с ними делать, вы можете сделать их статическими переменными внутри статических функций-членов:
// header file
class A {
public:
static void func();
};
// cpp file
void A :: func() {
static int avar = 0;
// do something with avar
}
Я предполагаю, что все сводится к тому, имеют ли эти переменные какое-то реальное значение в контексте класса (например, указатель на какую-то общую память, используемую всеми объектами) или просто какие-то временные данные, которые вам нужно передавать между методами и не загромождать класс с. В последнем случае я бы определенно выбрал безымянное пространство имен. В первом я бы сказал, что это вопрос личного вкуса.
Я частично согласен с Грегом в том, что безымянные члены пространства имен инкапсулированы не более, чем личные данные. В конце концов, смысл инкапсуляции в том, чтобы скрыть детали реализации от других модулей, а не от других программистов. Тем не менее, я думаю, что в некоторых случаях это полезная техника.
Рассмотрим следующий класс:
class Foo {
public:
...
private:
static Bar helper;
};
В этом случае любой модуль, который хочет использовать Foo, также должен знать определение Bar, даже если это определение не имеет никакого отношения к делу. Такого рода зависимости заголовков приводят к более частым и длительным перестроениям. Перемещение определения помощника в безымянное пространство имен в Foo.cpp — отличный способ сломать эту зависимость.
Я также категорически не согласен с тем, что безымянные пространства имен каким-то образом менее удобочитаемы или менее удобны в сопровождении, чем статические элементы данных. Удаление ненужной информации из заголовка делает его более лаконичным.