문제
일부 오래된 코드를 리팩토링하는 동안 a) 멤버 데이터에 대해 작동하지 않거나 다른 멤버 함수를 호출하지 않고 b) 다른 곳에서 유용할 수 있기 때문에 실제로 정적이어야 하는 여러 공개 메서드를 제거했습니다.
이로 인해 '도우미' 기능을 함께 그룹화하는 가장 좋은 방법에 대해 생각하게 되었습니다.Java/C# 방식은 개인 생성자와 함께 정적 함수 클래스를 사용하는 것입니다. 예:
class Helper
{
private:
Helper() { }
public:
static int HelperFunc1();
static int HelperFunc2();
};
그러나 C++이므로 네임스페이스를 사용할 수도 있습니다.
namespace Helper
{
int HelperFunc1();
int HelperFunc2();
}
대부분의 경우 저는 네임스페이스 접근 방식을 선호한다고 생각하지만 각 접근 방식의 장단점이 무엇인지 알고 싶었습니다.예를 들어 클래스 접근 방식을 사용하면 오버헤드가 발생합니까?
해결책
오버헤드는 문제가 되지 않지만 네임스페이스에는 몇 가지 장점이 있습니다.
- 다른 헤더에서 네임 스페이스를 다시 열고 컴파일 종속성을 낮게 유지하면서 더 논리적으로 그룹화 할 수 있습니다.
이점에 네임 스페이스 별명을 사용할 수 있습니다 (디버그/릴리스, 플랫폼 특정 헬퍼, ....)
예를 들어나는 다음과 같은 일을 해왔습니다.
namespace LittleEndianHelper { void Function(); } namespace BigEndianHelper { void Function(); } #if powerpc namespace Helper = BigEndianHelper; #elif intel namespace Helper = LittleEndianHelper; #endif
다른 팁
사용할 수 있는 사례 class
(또는 struct
) 위에 namespace
유형이 필요한 경우입니다. 예를 들면 다음과 같습니다.
struct C {
static int f() { return 33; }
};
namespace N {
int f() { return 9; }
}
template<typename T>
int foo() {
return T::f();
}
int main() {
int ret = foo<C>();
//ret += foo<N>(); // compile error: N is a namespace
return ret;
}
Pieter의 뛰어난 응답에 덧붙이자면, 네임스페이스의 또 다른 장점은 다른 곳의 네임스페이스에 넣은 선언 항목, 특히 구조체를 전달할 수 있다는 것입니다.
//Header a.h
// Lots of big header files, spreading throughout your code
class foo
{
struct bar {/* ... */);
};
//header b.h
#include a.h // Required, no way around it, pulls in big headers
class b
{
//...
DoSomething(foo::bar);
};
그리고 네임스페이스를 사용하면...
//Header a.h
// Big header files
namespace foo
{
struct bar {/* ... */);
}
//header b.h
// Avoid include, instead forward declare
// (can put forward declares in a _fwd.h file)
namespace foo
{
struct bar;
}
class b
{
//...
// note that foo:bar must be passed by reference or pointer
void DoSomething(const foo::bar & o);
};
Forward 선언은 수백 개의 소스 파일에 걸쳐 있는 프로젝트를 마친 후 작은 헤더 변경 후 컴파일 시간에 큰 차이를 만듭니다.
Paercebal에서 편집
열거형 오류로 인해 종료되도록 하기에는 답변이 너무 좋았습니다(댓글 참조).열거형(현재 C++에서는 지원되지 않고 C++0x에서만 전방 선언 가능)을 구조체로 대체했습니다.
네임스페이스 사용의 가장 큰 장점은 네임스페이스를 다시 열고 나중에 더 많은 항목을 추가할 수 있다는 것입니다. 클래스에서는 그렇게 할 수 없습니다.이는 느슨하게 결합된 도우미에 대해 이 접근 방식을 더 좋게 만듭니다(예를 들어 모든 STL이 ::std에 있는 것처럼 전체 라이브러리에 대한 도우미 네임스페이스를 가질 수 있습니다).
클래스의 가장 큰 장점은 클래스를 사용하여 클래스 내에 중첩할 수 있다는 것입니다. 클래스에 네임스페이스를 중첩할 수는 없습니다.이는 밀접하게 결합된 도우미에 대해 이 접근 방식을 더 좋게 만듭니다.
클래스와 네임스페이스에 추가 오버헤드가 발생하지 않습니다.
네임스페이스는 Koenig 조회의 추가적인 이점을 제공합니다.도우미 클래스를 사용하면 코드가 더 장황해질 수 있습니다. 일반적으로 호출에 도우미 클래스 이름을 포함해야 합니다.
네임스페이스의 또 다른 이점은 나중에 가독성이 좋다는 것입니다.클래스의 경우 나중에 특정 클래스가 객체를 생성하는 데 사용되지 않는다는 점을 상기시키기 위해 "도우미"와 같은 단어를 포함해야 합니다.
실제로는 둘 다 오버헤드가 없습니다.컴파일 후에는 사용되는 이름만 다릅니다.
내 답변의 일부를 복사/잘라내기/재작업했습니다. C++에서 네임스페이스를 어떻게 적절하게 사용합니까?.
"사용하다"를 사용하다
도우미 함수의 "접두사"를 반복하지 않으려면 "using"을 사용할 수 있습니다.예를 들어:
struct AAA
{
void makeSomething() ;
} ;
namespace BBB
{
void makeSomethingElse() ;
}
void willCompile()
{
AAA::makeSomething() ;
BBB::makeSomethingElse() ;
}
void willCompileAgain()
{
using BBB ;
makeSomethingElse() ; // This will call BBB::makeSomethingElse()
}
void WONT_COMPILE()
{
using AAA ; // ERROR : Won't compile
makeSomething() ; // ERROR : Won't compile
}
네임스페이스 구성
네임스페이스는 패키지 그 이상입니다.또 다른 예는 Bjarne Stroustrup의 "The C++ 프로그래밍 언어"에서 찾을 수 있습니다.
"스페셜 에디션"에서는 8.2.8 네임스페이스 구성, 에서 그는 두 개의 네임스페이스 AAA 및 BBB를 CCC라는 또 다른 네임스페이스로 병합하는 방법을 설명합니다.따라서 CCC는 AAA와 BBB의 별칭이 됩니다.
namespace AAA
{
void doSomething() ;
}
namespace BBB
{
void doSomethingElse() ;
}
namespace CCC
{
using namespace AAA ;
using namespace BBB ;
}
void doSomethingAgain()
{
CCC::doSomething() ;
CCC::doSomethingElse() ;
}
다양한 네임스페이스에서 선택한 기호를 가져와서 자신만의 사용자 정의 네임스페이스 인터페이스를 구축할 수도 있습니다.나는 아직 이것의 실제적인 용도를 찾지 못했지만 이론적으로는 멋지다.
나는 도우미 함수를 만들 때 익명 네임스페이스를 사용하는 경향이 있습니다.(일반적으로) 해당 모듈을 관리하는 모듈에서만 볼 수 있으므로 종속성을 제어하는 좋은 방법입니다.