2

템플릿 클래스에 대한 질문이 있습니다. 예를 들어, 내가 dllexport와 CPP 파일에 비 전문적인 방법을 정의 할 수 있도록하고 싶습니다, 이제이 클래스템플릿 클래스의 C++ 비 전문 멤버

template<class TBase> class CTemplateInherit : public TBase 
{ 
public: 

    virtual void DoNonSpecializedWork(); 
    virtual void DoTemplateWork(); 
    virtual ~CTemplateInherit(); 
}; 

// In header file 
template<class TBase> 
bool CTemplateInherit<TBase>::DoTemplateWork() 
{ 
    std::wcout << L"CTemplateInherit::DoTemplateWork" << std::endl; 
    TBase::DoWork(); 
    return true; 
} 

// In CPP file 
bool CTemplateInherit::DoNonSpecializedWork() 
{ 
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl; 
    return true; 
} 

을, 단지 헤더에 전문을 유지한다. 일반적으로 템플릿 메소드로 멤버 메소드를 정의 할 수는 있지만 TBase를 상속 받고 있기 때문에 가능하지 않습니다.

그래서 어떻게 나눌 수 있습니까? TBase의 4 가지 메소드 만 오버라이드하고 DLL 파일의 DLLEXPORT를 다른 40 가지 방법으로 유지할 수 있으며, 특수화는 헤더 파일에 있습니다.

미리 제안 해 주셔서 감사합니다.

+2

템플릿 매개 변수없이 'CTemplateInherit :: DoNonSpecializedWork'가 컴파일되지 않아야합니다. 맞습니까? – Vlad

+0

모든 비 특화된 메소드를 구현하고, template class CTemplateInherit : public TBase, public TNonspecialized'를 선언하는 중간의 비 템플릿 화 된'TNonspecialized'를 생성 할 수 있습니까? – Vlad

+0

감사합니다! 아니요, 물론 컴파일되지 않습니다. 그것은 내가하고 싶었던 것과 더 비슷했습니다. 두 클래스에서 상속을 생각하고 있었지만 하나의 멤버 함수에 대한 함수 호출은 모호합니다. 비록 당신이 제안한 것처럼 나는 그 라인을 따라 뭔가를하려고 여전히 생각하고 있지만. – namezero

답변

1

를 인스턴스화 할 수 있습니까? 이것이 여기서 핵심적인 문제입니다.

그렇지 않은 경우 비 전문화 된 메소드에 대해 다른 클래스를 작성하고 CTemplateInherit 클래스의 두 클래스에서 (공개적으로) 상속 할 수 있습니다. 문제 해결됨.

그러나, 비 전문적인 방법이 TBase 클래스의 가상 메소드를 오버라이드 (override)하는 경우는, 다음은 약간 더 복잡하다 :

솔루션은 1) 모든 비 - 전문 기능을 가지고 하나로 재 그룹 "세부 사항 " 머리글. 템플릿이 아닌 (템플릿이 아닌) 자유 함수 그룹 (입출력을 매개 변수로 전달하기가 쉬운 경우) 또는 필요하지 않은 특수 데이터 멤버를 사용하여 (비 템플릿) 클래스로 제공됩니다. 그런 다음, 해당 cpp 파일 (나중에 DLL로 컴파일)에서 모든 함수를 정의 (구현)합니다.

그런 다음 CTemplateInherit 클래스 템플릿에서 비 특수 함수 호출을 "detail"함수 세트로 전달하면됩니다. 템플릿은 기본적으로 인라인이므로 오버 헤드는 없습니다. "세부 사항"기능을 하나의 클래스 (템플릿이 아님)로 재 그룹화해야한다면 private 계승을 사용하여 함수 이름 충돌을 방지하십시오. 그런 다음 다른 상속 된 데이터 멤버와 마찬가지로 "detail"클래스의 데이터 멤버에 액세스 할 수 있으며 특수한 함수 호출을 DLL로 컴파일 할 수있는 "detail"클래스 구현에 전달할 수 있습니다. DLL에서 클래스를 내보내는 데 적합한 프레임 워크 (일반 C++에는 신뢰할 수있는 메커니즘이 없기 때문에)하지만 사용자의 질문은 암시적인 것 같습니다.

이 솔루션의 유일한 문제는 몇 가지 간단한 전달 기능을 성가신 것으로 만듭니다. 하지만 IMHO는 DLL에서 구현을 제거하는 데 드는 비용으로 합리적인 가격입니다 (거의 언제든지 원하는대로 래퍼 함수를 ​​작성해야합니다).

해결 방법 2) 기본 클래스에서 특수화되지 않은 가상 함수 세트가있는 경우 해당 하위 세트는 실제로 TBase의 실제 유형에 종속되지 않습니다. (즉, 해당 함수의 프로토 타입은 해당 클래스없이 프로토 타입을 만들 수 있습니다.). 그러면 해당 하위 집합을 TBase에서 상속받을 것으로 예상되는 다른 기본 클래스로 다시 그룹화 할 수 있습니다. TNonSpecialBase이라고합시다. 이 시점에서, 당신은 다음과 같은 계층 구조를 설정할 수 있습니다

class TNonSpecialBase { 
    // set of pure-virtual functions that are not special. 
}; 

// this is an example of a class that could act as a TBase: 
class TExampleBase : public virtual TNonSpecialBase { 
    // set of virtual functions that are special to TExampleBase. 
}; 

class CNonSpecialDerived : public virtual TNonSpecialBase { 
    // declaration of non-specialized functions that override the function in TNonSpecialBase. 
}; 

template <typename TBase> 
class CTemplateInherit : public TBase, public CNonSpecialDerived { 
    // set of virtual functions that are specialized for the template argument TBase. 
}; 

위의 설치와를 전문 기능 CTemplateInherit의 헤더 파일에서 생을 마감해야하지만 비 전문 기능을 정의 할 수 있습니다 CNonSpecialDerived에서 전열을 정비 별도의 cpp 파일에서 (그리고 DLL로 컴파일 된). 마술 트릭은 가상 클래스를 사용하여 최종 클래스가 기본 클래스 TNonSpecialBase에 대한 단일 가상 테이블을 가질 수있게합니다. 다시 말해, CNonSpecialDerived 클래스는 TNonSpecialBase에서 상속 된 TBase의 가상 함수를 무시할 수 있습니다. 단, TBase가 해당 함수를 무시하지 않는 한 컴파일러에서 모호함이라고합니다. 이 방법으로 사용자는 TBase 개체에 대한 포인터를 처리 할 수 ​​있으며 가상 함수를 호출하여 CTemplateInherit 구현 (특수화) 또는 CNonSpecialDerived 구현 (아마도 DLL)으로 전달할 수 있습니다.

+0

정말 고마워요! 이것이 제가 끝내 준 것입니다. TBase와 템플릿이없는 클래스를 상속합니다.본질적으로 클래스는 확장 된 기능을 가진 파생 클래스로 작동해야하지만 복수 클래스가 사용할 수 있습니다. 여기에 이미지를 업로드 할 수 있다면 데모 용으로 사용할 것입니다. – namezero

+0

감사합니다. 위의 편집 된 게시물을 참조하십시오 (나는 평판 포인트가 10없이 답할 수 없습니다). – namezero

3

클래스의 hierarchy을 변경하지 않으려는 경우.

1) specialize.cpp 파일에 필요한 모든 유형의 기능.

template<> 
bool CTemplateInherit<First>::DoNonSpecializedWork() 
{ 
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl; 
    return true; 
} 

template<> 
bool CTemplateInherit<Second>::DoNonSpecializedWork() 
{ 
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl; 
    return true; 
} 

template<> 
bool CTemplateInherit<Nth>::DoNonSpecializedWork() 
{ 
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl; 
    return true; 
} 

2) .cpp 파일에

template<typename T> 
bool CTemplateInherit<T>::DoNonSpecializedWork() 
{ 
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl; 
    return true; 
} 

를 사용하지만, 디트 마르 제안 header

template class CTemplateInherit<First>; 
template class CTemplateInherit<Second>; 
template class CTemplateInherit<Nth>; 

3) 으로이 같은 것을 사용합니다.

+0

감사. 위의 편집 된 게시물을 참조하십시오 (나는 평판 포인트가 10없이 답할 수 없습니다). – namezero

3

나는 당신이 성취하려고 시도하는 것이 확실하지 않지만 템플릿을 사용할 때 이것이 필요에 따라 인스턴스화되어 있는지 확인해야합니다. 템플릿 정의를 헤더에 넣으면 컴파일러에서 암시 적 인스턴스화를 얻을 수 있습니다. 함수 템플릿이 사용되고 볼 수있는 템플릿의 정의가있을 때마다 템플릿을 인스턴스화합니다. 템플릿을 다른 곳에두면 컴파일러는 필요할 때 템플릿 정의를 볼 수 없으므로 암시 적으로 템플릿을 인스턴스화하지 않습니다. TBase 클래스의 가상 메소드를 오버라이드 (override) 비 전문적인 방법 위치 : 그러나, 당신은 내가 누락 된 정보 중 하나 개 중요한 부분이 있다고 생각 : 예컨대, 해당 함수가 자신을 템플릿

// In CPP file 
template <class TBase> 
bool CTemplateInherit<TBase>::DoNonSpecializedWork() 
{ 
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl; 
    return true; 
} 

template bool CTemplateInherit<SomeBase>::DoNotSpecializeWork(); 
template bool CTemplateInherit<SomeOtherBase>::DoNotSpecializeWork(); 
+0

어쩌면 내가 왜 이것이 원하는지 분명히해야한다. DLL에 정의 된 리소스에 액세스하는 특수하지 않은 메서드가 있으므로 헤더에 정의 된 리소스를 사용하면 LoadString()과 함께 사용할 때 리소스를 찾지 못합니다. 그래서 DLL의 컨텍스트에서 정의되고 실행될 필요가 있습니다. 두 개의 기지에서 상속하는 것이 아마도이 경우에 가장 합리적 일 것이라고 생각합니까? – namezero

+0

감사합니다. 위의 편집 된 게시물을 참조하십시오 (나는 평판 포인트가 10없이 답할 수 없습니다). – namezero

관련 문제