본문 바로가기
Object Oriented Programming(C++)/Effective C++

Effective C++ | 항목 43 템플릿으로 만들어진 부모 클래스 안의 이름에 접근하는 방법을 알아두자

by continue96 2024. 8. 6.

Effective C++ 항목 43

 

항목 43 템플릿으로 만들어진 부모 클래스 안의 이름에 접근하는 방법을 알아두자

43.1 부모 클래스 템플릿

  • 부모 템플릿 클래스를 상속받은 자식 클래스에서 부모 클래스에 있는 함수를 호출할 수 없다.
    • T가 템플릿 매개변수이므로 인스턴스화하기 전까지 MsgSender<T> 클래스가 어떤 형태인지 알 수 없다.
    • 즉, SendRaw 함수가 MsgSender<T>에 있는지 알 수 없으므로 컴파일 오류가 발생한다.
class CompanyA
{
public:
	void SendRawText(const std::string& _strMsg) { ... }
	void SendEncryptedText(const std::string& _strMsg) { ... }
};

class CompanyZ
{
public:
	void SendEncryptedText(const std::string& _strMsg) {}
};

class MsgInfo { ... };

template<typename T>
class MsgSender
{
public:
	void SendRaw(const MsgInfo& _oMsgInfo)
	{
		std::string strMsg = "";

		T oCompany;
		oCompany.SendRawText(strMsg);
	}

	void SendEncrypted(const MsgInfo& _oMsgInfo)
	{
		std::string strMsg = "";

		T oCompany;
		oCompany.SendEncryptedText(strMsg);
	}
};

template<typename T>
class LogMsgSender : public MsgSender<T>
{
public:
	void SendLogRawMsg(const MsgInfo& _oMsgInfo)
	{
		// C3861 'SendRaw': 식별자를 찾을 수 없습니다
		SendRaw(_oMsgInfo);
	}
};

 

 

  • 완전 템플릿 특수화(total template specialization)
    • 클래스 템플릿이 특정한 타입으로 특수화되었고 이때 템플릿 매개변수들이 완전히 특정한 타입으로 특수화된 경우를 말한다.
    • 즉, T가 CompanyZ 타입인 경우, SendRaw 함수가 없다.
    • 부모 클래스 템플릿이 특수화될 수 있기 때문에 컴파일러는 부모 템플릿 클래스에서 상속된 이름을 찾지 않는다.
// MsgSender 템플릿 클래스를 CompanyZ 타입으로 특수화합니다.
template<>
class MsgSender<CompanyZ>
{
public:
	void SendEncrypted(const MsgInfo& _oMsgInfo)
	{
		std::string strMsg = "";

		CompanyZ oCompany;
		oCompany.SendEncryptedText(strMsg);
	}
};

 

 

43.2 자식 클래스 템플릿에서 부모 클래스 템플릿 참조

  • 자식 클래스 템플릿에서 부모 클래스 템플릿을 참조하는 세 가지 방법이 있다.
    • 부모 클래스 함수를 호출하는 코드 앞에 this->를 작성한다.
    • using 선언으로 부모 클래스의 이름을 자식 클래스의 유효 범위 안으로 확장한다.
    • 부모 클래스 함수를 호출하는 코드 앞에 부모 클래스라는 것을 명시한다. 단, 가상 함수인 경우, 동적으로 바인드되지 않으므로  추천하지 않는다.
  • 컴파일러는 자식 클래스 템플릿의 정의를 분석할 때(이른 진단), 자식 클래스 템플릿이 인스턴스화될 때(늦은 진단)로 나누어 부모 클래스 멤버에 대한 참조가 유효한지 판단한다.
template<typename T>
class LogMsgSender : public MsgSender<T>
{
public:
	// 1. 컴파일러에게 부모 클래스에 SendRaw 함수가 있다고 가정하게 합니다.
	using MsgSender<T>::SendRaw;

	void SendLogRawMsg(const MsgInfo& _oMsgInfo)
	{
		// 2. 컴파일러에게 SendRaw 함수가 상속된 것으로 가정하게 합니다.
		this->SendRaw(_oMsgInfo);

		// 3. 컴파일러에게 SendRaw 함수가 상속된 것으로 가정하게 합니다.
		MsgSender<T>::SendRaw(_oMsgInfo);
	}
};

 

NOTE
① 자식 클래스 템플릿에서 부모 클래스 템플릿 안에 있는 이름을 참조하려면 this-> 접두사를 붙이거나 명시적으로 using 선언한다.

댓글