2010-05-08 7 views
6

함께 그룹화 할 수 있지만 일부 개체/엔티티에 속하지 않으므로 메서드로 처리 할 수없는 몇 가지 기능이 있습니다.C++ 네임 스페이스 및 템플릿

기본적으로이 상황에서는 새로운 네임 스페이스를 만들고 파일에 정의를 넣습니다. 구현은 cpp 파일입니다. 또한 (필요한 경우) 그 cpp 파일에 익명의 네임 스페이스를 만들고 거기에 내 네임 스페이스의 인터페이스에 노출 시키거나 포함 할 필요가없는 모든 추가 기능을 넣을 것입니다.

샘플 코드 (header) (... 난 그냥 더 나은 샘플 생각할 수 없다 아마 최고의 예를 더 나은 다른 프로그램 아키텍처 할 수 있지만) 아래의 코드를 참조하십시오

namespace algorithm { 
    void HandleCollision(Object* object1, Object* object2); 
} 

샘플 코드 (cpp)

#include "header" 

// Anonymous namespace that wraps 
// routines that are used inside 'algorithm' methods 
// but don't have to be exposed 
namespace { 
    void RefractObject(Object* object1) { 
     // Do something with that object 
     // (...) 
    } 
} 

namespace algorithm { 
    void HandleCollision(Object* object1, Object* object2) { 
     if (...) RefractObject(object1); 
    } 
} 

지금까지 그렇게 좋았습니다.이 코드는 내 코드를 관리하는 좋은 방법이라고 생각합니다.하지만 템플릿 기반 함수가 있고 기본적으로 동일한 작업을 수행하려는 경우 어떻게해야합니까?

템플릿을 사용하는 경우 모든 코드를 header 파일에 넣어야합니다. 그렇다면 구현 세부 사항을 어떻게 숨길 수 있습니까?

나는 내 인터페이스에서 RefractObject 기능을 숨기려하지만 단순히

(나는 header 파일에있는 모든 내 코드를해서) 내가 생각 해낸 유일한 접근 방식을 선언을 제거 할 수 없습니다 같은되었습니다

샘플 코드 (header)

namespace algorithm { 
    // Is still exposed as a part of interface! 
    namespace impl { 
     template <typename T> 
     void RefractObject(T* object1) { 
     // Do something with that object 
     // (...) 
     } 
    } 

    template <typename T, typename Y> 
    void HandleCollision(T* object1, Y* object2) { 
     impl::RefractObject(object1); 
     // Another stuff 
    } 
} 

모든 아이디어를 어떻게 코드 설계의 관점에서이 더 나은 만드는 방법?

답변

7

꽤 일반적인 해결책입니다. Boost는 그것을 수행하고 그것을 수행하지만 대신 detail 네임 스페이스를 사용합니다. 그냥 규칙으로 만드십시오 : "detail을 들여다 보지 마십시오!"

파일을 사용하여 세부 정보를 제공하고 세부 정보 폴더에 넣어 두는 것이 좋습니다.

이것은 일반적으로 단지 좋은 코드 연습이다
//   v 
#include "detail/RefractObject.hpp" 

namespace algorithm { 

    template <typename T, typename Y> 
    void HandleCollision(T* object1, Y* object2) { 
     detail::RefractObject(object1); 
     // Another stuff 
    } 
} 

(일을 분할하고 재사용 가능한 유지가)와 구현 세부 사항의 헤더 파일 청소기를 유지한다 : 즉, 내 코드에 가깝다 것입니다.

1

먼저 컴파일하지 않으면 사용자가 소스를 숨길 수 없으며 템플릿을 사용하여 소스를 숨길 수는 없습니다. 그래서 어떤 의미에서는 귀찮게하지 말 것을 제안합니다.

Refract가 멤버 메소드가 될 수없는 이유는 무엇입니까?

+0

구성원 중에서 무엇보다 자유 함수가 선호됩니다 :) – GManNickG

+0

글쎄, 여기에는 샘플 용이라고 나와 있습니다. 내 실제 프로젝트의 경우 알고리즘은 근사 알고리즘과 경로 찾기 알고리즘을 포함하고 있기 때문에 Intellisense가 발명 된 이래로 그 단어의 의미에서 '멤버'로만 만들 수는 없습니다 ... –

+0

멤버 함수> 무료 함수. – Puppy

2

"정적 클래스"빌드 - 네임 스페이스 대신 동일한 이름의 클래스를 선언하십시오.생성자, 소멸자, 복사 및 대입 연산자를 private로 만든 다음 독립 실행 형 함수를 모두 정적 멤버 함수로 만듭니다.

템플릿 예 : 모든 당신이 수 형 - 당신은 모든 기능의 버전을 보장,
1) 전체 클래스를 템플릿 수 있습니다 여기에

template<class T> 
class StringOperator 
{ 
friend SomeOtherLibraryClass; // Let it use "Hidden()" 
private: 
    StringOperator() {} 
    ~StringOperator() {} 
    StringOperator(const StringOperator&); 
    StringOperator& operator=(const StringOperator&); 

    static bool Hidden(const T& input) { 
     // Hidden routine end-users shouldn't see... 
    } 

public: 
    static void YourFunction(T& parameter) { 
     // Some public code.... 
    } 

    static T  AnotherRoutine(const T* ptr) { 
     // Some public code... 
    } 
}; 

은 몇 가지 장점 대 네임 스페이스입니다 유형에 따라 기능을 추가/제거하는 기능도 있습니다.
2) 비공개 개체 및 필요한 메서드에 대한 선언을 숨길 수있는 비공개 영역이 있습니다
3) "친구"메커니즘을 통해 "SomeOtherLibraryClass"와 같은 다른 개체에 이없는 함수를 사용할 수 있습니다. 이를 최종 사용자에게 공개합니다.

최종 사용자는 "StringOperator :: FunctionName()"을 사용하여 함수에 액세스 할 수 있으며 대신 "StringOperator :: FunctionName()"을 제공하기 위해 함수를 템플릿으로 만들 수 있습니다. 후자는 네임 스페이스의 함수에 액세스 할 때 사용하는 것과 동일한 패턴입니다.

0

나는 잠시 동안 똑같은 생각을했습니다. 결국 코드를 ​​더 이식성 있고 재사용 가능하며 일반적으로 사용할 수 있도록 클래스를 사용하기로 결정했습니다.

  • 클래스를 사용하면 특성, 태그 지정 및 정책과 같은 모든 종류의 메타 프로그래밍을 수행 할 수 있습니다.
  • 클래스는 이미 공개, 비공개 및 보호되어 있습니다.

당신이 네임 스페이스를 사용하는 이유 유일한 두 가지 이유 : 시각적 노이즈를 줄이기 위해

  • boost::for_each
  • std::for_each 이름 충돌을 해결하기 위해이. 예를 들어 using namespace boost::filesystem::없이 해당 기능을 호출 할 수 있습니다.

도이 두 경우에 .::보다 짧은, fs.mkdir(). 플러스로 우리에게 그것을, 당신은 방법이있는 클래스를 상속 할 수 있습니다 또는 (시작하여 my_own_filesystem_methods fs;의 이름을 변경합니다.

을 다른 혜택이 있습니다 std::cout << "hi" << endl;과 같은 네임 스페이스를 사용하지만 그다지 중요하지는 않습니다.