Частное пространство имен в исходных файлах
У меня есть сомнения относительно частных методов и функций.
Скажем, у меня есть некоторые утилиты, которые не обязательно должны быть внутри класса. Но те же самые методы требуют вызова других, которые я не хочу показывать пользователю. Например:
Suspect.h
namespace Suspect {
/**
* \brief This should do this and that and more funny things.
*/
void VerbalKint(void); // This is for you to use
}
Suspect.cpp
namespace Suspect {
namespace Surprise {
/**
* \brief The user doesn't need to be aware of this, as long
* the public available VerbalKint does what it should do.
*/
void KeyserSoze(void) {
// Whatever
}
} // end Surprise
void VerbalKint(void) {
Surprise::KeyserSoze();
}
}
Итак, этот макет работает. При включении Suspect.h
отображается только VerbalKint
.
Это может быть достигнуто также с использованием класса и маркировки VerbalKint
как static:
class Suspect {
public:
// Whatever
static void VerbalKint(void);
private:
static void KeyserSoze(void);
};
Я хотел бы знать, есть ли разница между этими двумя подходами. Лучше (быстрее, проще поддерживать), чем другой?
Каковы ваши мысли?
Ответы
Ответ 1
Если функции "свободные", вы должны использовать анонимное пространство имен в *.cpp
:
namespace Suspect {
namespace Surprise {
namespace {
void KeyserSoze(void) {
// Whatever
}
} // end anon
} // end Surprise
} // end Suspect
или даже:
namespace {
void KeyserSoze(void) {
// Whatever
}
} // end anon
Это держит его подальше от клиентов, чтобы они не могли получать доступ, зависать или сталкиваться с вашим экспортом при связывании. Он также содержит ненужные декларации от них, уменьшая время их компиляции и потенциально связывая время или двоичные размеры, если определения видны. Наконец, это делает его конфиденциальным, поэтому они не могут зависеть от него, и вам не нужно поддерживать его для их использования. Вы можете передать их во внешний мир, если вы выберете (указатель функции в случае KeyserSoze()
).
В других случаях предпочтительно объявлять частную функцию-член в вашем классе, а затем определять ее в *.cpp
(где это возможно). Как правило, вы выбираете этот подход, когда вам нужно более тесное отношение к классу (например, когда вам нужен доступ к некоторым членам). Вы сказали, что это не так в вопросе, но я просто повторяю, когда следует использовать частных членов.
Ответ 2
Лучший подход - определить все вспомогательные функции в неназванном пространстве имен в Suspect.cpp
, а не в пространстве имен Suspect::Surprise
.
В вашем случае это будет:
namespace{
void KeyserSoze(){ ... };
}
Вы можете просто вызвать KeyserSoze
без каких-либо спецификаторов пространства имен из Suspect.cpp
.
Вы можете найти более подробную информацию об этом здесь: Без имени/анонимного пространства имен или статические функции
Другой альтернативой является объявление KeyserSoze
как static
, но это не рекомендуется стандартом. Стандарт С++ читается в разделе 7.3.1.1. Пространства имен, абзац 2:
Использование статического ключевого слова устарело при объявлении объектов в области пространства имен, пространство имен без имени обеспечивает превосходную альтернативу
Ответ 3
На самом деле, хотя функция не видна глазу, когда вы не объявляете ее ни в каком заголовке; он все еще доступен для пользователя, если они пишут декларацию.
В С++ механизм скрыть символы, объявленные на уровне файла:
-
static
для (глобальных) переменных и функций
-
namespace { ... }
(анонимные пространства имен) для всего, что вы пожелаете (более общий, более подробный)
Например:
// Suspect.cpp
namespace Suspect {
static void KeyserSore() {}
void VerbalKing() { KeyserSore(); }
}
Ответ 4
Основное различие между помещением чего-либо в класс или пространство имен заключается в том, что вы не можете добавлять дополнительные статические функции в класс в другой заголовочный файл.
Это:
хиджры
namespace Fred {
void Somefunc();
}
b.h
namespace Fred {
void Anotherfunc();
}
работают, хотя ни один, ни b не знают, что друг другу сделали с их пространствами имен. Это может вызвать проблемы, такие как:
c.h
namespace Fred {
void Thirdfunc();
}
d.h
namespace Fred {
bool Thirdfunc();
}
который все отлично и денди, пока вы не запустите программу...
Это, хотя и невозможно, гораздо менее вероятно с классами.
В вашем примере, только с одним исходным файлом, вы также можете рассмотреть использование анонимного пространства имен, поскольку это ограничивает объявления файловой областью, поэтому люди вне вашего файла не могут получить к ним доступ (или столкнуться с ними) случайно.