2011-01-24 11 views
0

작성하려고하는 C++ 라이브러리에 문제가 있습니다. 그것은 보통 설치, 하나의 cpp 파일, 하나의 헤더 파일입니다. 나는 헤더 파일이 단지 (예를 들어 추상적 인 기본 클래스를 가지고 있는데, 나는 헤더 파일에서 원하지 않는) 사용되도록 의도 된 부분을 드러내 길 원한다. 지금까지는 하나의 파일로 작업하고 있습니다 (아무 것도 신경 쓰지 않는 전처리 기가 포함되어 있기 때문에 아무런 차이가 없어야한다고 가정합니다).C++ 클래스 선언 및 네임 스페이스

"헤더 파일"은 헤더 구현 파일 전후의 두 지점에 걸쳐 있습니다.

#include <stdio.h> 

// lib.h 
namespace foo { 
    template <class T> class A; 
} 

// lib.cpp 
namespace foo { 
    template <class T> class A { 
     private: 
     T i; 
     public: 
     A(T i) { 
      this->i = i; 
     } 

     T returnT() { 
      return i; 
     } 
    }; 
}; 

// lib.h 
namespace foo { 
    template <class T> T A<T>::returnT(); 
} 

// foo.cpp 
void main() { 
    foo::A<int> a = foo::A<int>(42); 
    printf("a = %d",a.returnT()); 
} 

그래서 자연스럽게, 난 그냥

namespace foo { 
    template <class T> class A; 
    template <class T> T A<T>::returnT(); 
} 

하지만 내 컴파일러는 returnTfoo::A<T>의 구성원이 아닌 불평 (이 좋아하지 않는를 포함하도록 내 헤더 파일을 싶습니다. 그 이유를 I 클래스 선언 자체를 헤더에 넣고 싶지 않다면 (내가 이해 한대로) 숨기고 싶은 모든 사적인 것과 비슷한 것들을 숨길 수 있습니다.

아마 나, 하지만 다음 헤더 파일은 적어도 "좋지 않은"것 같습니다. "인터페이스 명세"이다.이 라이브러리는 A의 내부 구조를 노출하는데, lib의 사용자는이를 알 필요가 없다.

// lib.h 
namespace foo { 
    template <class T> class A { 
     private: 
     int i; 
     public: 
     A(T); 
     T returnT(); 
    }; 
} 

// lib.cpp 
namespace foo { 
    template <class T> A<T>::A(T i) { 
     this->i = i; 
    } 
    template <class T> T A<T>::returnT() { 
     return i; 
    } 
}; 

허용되는 방식입니까? 가능하다면 더 추상적 인 헤더 파일을 원합니다.

+0

코드의 전체 첫 번째 블록 헤더 파일의 코드인가? "lib.h"라는 레이블이 붙은 두 개의 블록이 있기 때문에 혼란 스럽지만 그곳에는'main' 함수가 있습니다. –

+0

'template'이라는 단어를 쓸 때 구현 세부 사항을 공개하는 데 사용됩니다. 이것은 그것이 작동하는 방법, 기간입니다. 메인 헤더에'#include '하는 "구현 헤더 파일"을 만들 수 있지만 소스를 제공해야합니다. –

+0

@James McNellis : 첫 번째 코드 조각 (회색 블록)은 모든 것을 하나의 파일로 유지하는 데 사용 된 테스트 파일입니다. 이것은'lib.h','lib.cpp'와'main.cpp'의 세 파일로 나뉘어지며 마지막은'lib'를 호출하는 "user"테스트입니다. 문제는 내가 원한 것처럼 보이는 것을 얻으려면 머리말을 구현 코드 위의 한 부분으로, 그리고 그 아래의 한 부분으로 분할해야한다는 것입니다. 말이 돼? – Svend

답변

2

여기에서 다루고있는 .CPP 파일 두 가지 문제가 있습니다 컴파일러 요구 (당신이 당신의 주()에서처럼) 당신은 스택에 해당 클래스의 인스턴스를 넣어하려는 경우

I. 가 (충분한 메모리를 할당하기 위해) 클래스의 크기를 알기 위해서. 그것을 위해서는 구성원을 알 필요가 있으며 그로 인해 완전한 선언이 필요합니다.

클래스의 레이아웃을 숨기는 유일한 방법은 인터페이스와 팩토리 메서드/함수를 작성하고 인스턴스를 팩토리의 힙에 배치하는 것입니다. 예를 들어

(템플릿없이, 이유를 알고 아래 참조) : 당신에

namespace foo { 
    class IA { 
    public: 
     virtual ~IA(); 
     virtual int returnT() = 0; 

     static IA *Create(); 
    }; 
} 

합니다.CPP는 당신이 다음을 수행하십시오 BTW

namespace foo { 
    class A : public IA { 
    private: 
     int i; 
    public: 
     A() : 
     i(0) { 
     } 
     virtual ~A() { 
     } 
     virtual int returnT() { 
     return i; 
     } 
    }; 
    IA::~IA() { 
    } 

    IA *IA::Create() { 
    return new A(); 
    } 
} 

: 스마트 포인터를 사용하는 것은 권장 할 것입니다 ...

II를. 템플릿을 사용하고 있으므로 메서드 정의는 헤더 파일을 통해 표시되거나 특정 유형의 집합에 대해 명시 적으로 인스턴스화되어야합니다.

lib.h :

namespace foo { 
    template <typename T> class IA { 
    public: 
     virtual ~IA() { 
     } 
     virtual T returnT() = 0; 

     static IA *Create(); 
    }; 
} 

lib_impl.h : 그래서 당신은

namespace foo { 
    template <typename T> class A : public IA<T> { 
    private: 
     T i; 
    public: 
     A() : 
     i(T()) { 
     } 
     virtual ~A() { 
     } 
     virtual T returnT() { 
     return i; 
     } 
    }; 

    template <typename T> IA<T> *IA<T>::Create() { 
    return new A<T>(); 
    } 
} 

그래서 당신은 lib.h과 lib_impl.h로 코드를 분할 할 수 있습니다 lib_impl.h를 포함시켜야한다. 는 lib.cpp를 추가 명시 적 인스턴스화를 사용하고 그냥 파일 lib_impl.h 포함 할 수 있도록 :

lib.cpp :

#include <lib_impl.h> 
namespace foo { 
    template class IA<int>; 
    template class A<int>; 
    template class IA<float>; 
    template class A<float>; 
    template class IA<char>; 
    template class A<char>; 
    // ... 
} 
+0

이 멋진 답변에 추가하려면 lib.h 끝에 lib_impl.h를 #include 할 수도 있습니다. 이런 식으로 사용자 관점에서 lib.h에 대해 간략하게 살펴보면 lib_impl.h의 세부 사항을 살펴볼 필요가 없으며 lib_impl을 알아낼 수있는 특별한 작업을 수행하지 않고도 필수 사항 (인터페이스)을 알 수 있습니다. .h를 포함시켜야합니다. –

+0

이 접근법 (FAQ에서도 간략히 설명 함)은 내가 끝내게 된 것입니다. 스마트 포인터는 내가 어디 있는지는 꽤 아니다;) – Svend

+0

질문이 있습니다. 내가 이해할 수 있듯이, lib.cpp는 어떤 템플릿을 생성 할 것인지에 대한 컴파일러에 대한 일종의 "힌팅"으로 사용됩니다. FAQ는 또한이 방법 (항목 35.13)을 언급하지만,이 구문은 구체적으로 무엇을하고 있습니까? Stroustrups 책에서 어디서 볼 수 있고 무엇인가 배울 수 있습니까? – Svend

5

템플릿의 정의를 선언과 분리 할 수 ​​없습니다. 둘 다 함께 헤더 파일에 들어가야합니다.

"왜?" 나는 "Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?"을 읽을 것을 권장합니다.


질문을 잘못 읽었을 수 있습니다. 또한 귀하의 질문에 어떻게 될 것인가 해결하기 위해이 유효하지 않습니다 : 그것은 같은 이유로 유효하지 않습니다

namespace foo { 
    template <class T> class A;  
    template <class T> T A<T>::returnT(); 
} 

이 유효하지 않음 :

namespace foo { 
    class A; 
    int A::returnT(); 
} 

멤버 함수 정의 내부에 선언해야합니다 수업의

+0

FAQ를 보면 문제가 무엇인지 명확하게 알 수 있습니다. 감사! – Svend

+0

@ 스벤드 : 예. 나는 도울 수있어서 기쁘다. –

관련 문제