Hyun2and

[Effective C++] 43: 템플릿으로 만들어진 기본 클래스 안의 이름에 접근하는 방법을 알아두자 본문

공부엔 끝이없다/Effective C++

[Effective C++] 43: 템플릿으로 만들어진 기본 클래스 안의 이름에 접근하는 방법을 알아두자

혀니앤 2023. 7. 23. 17:14
728x90

포인트

파생 클래스에서 기본 클래스 템플릿의 이름을 참조할 때는, this-> 를 붙이거나 기본 클래스 한정문을 명시적으로 써준다

 

예제 코드

(대부분은 비워놓은 내부 코드들)

 

#include <iostream>
using namespace std;

class CompanyA
{
public :
	void sendCleartext(const string& msg) {};
};

class CompanyB
{
public:
	void sendCleartext(const string& msg) {};
};

class CompanyZ
{
public:
	void sendCleartext(const string& msg) {};
};

class MsgInfo { };

template<typename Company>
class MsgSender
{
public:
	void SendClear(const MsgInfo& info)
	{
		string msg;

		Company C;
		C.sendCleartext(msg);
	}
};

template<typename Company>
class LoggingMsgSender : public MsgSender<Company>
{
public:
	void SendClearMsg(const MsgInfo& info)
	{
		SendClear(info); //차이가 생기는 부분!
	}
};

template<>
class MsgSender<CompanyZ>
{
public:
	void SendSecret()
	{

	}
};

int main() {
	MsgInfo info;

	LoggingMsgSender<CompanyA> LMSA;
	LMSA.SendClearMsg(info);
}

 

위의 구조를 가진 코드에서 SendClearMsg 를 호출하면 에러가 나오는 것을 알 수 있다

 

 

 

C3861 : 식별자를 찾을 수 없습니다 에러가 나온다. 

이유는 컴파일러가 LogginMsgSender 클래스 템플릿의 정의를 보고 어디서 파생된 것인지를 모른다는 것이다.

Company 는 템플릿 매개변수이고, 실제로는 인스턴스가 만들어질 때에서야 알게된다

 

 

MsgInfo info;

LoggingMsgSender<CompanyA> LMSA; //인스턴스를 생성하면서야 CompanyA를 쓸 것임을 알게됨
LMSA.SendClearMsg(info);

 

즉, Company 매개변수에 실제로 SendClear 가 있는지 없는지 모르겠기 때문에 그냥 컴파일 에러를 내버린다

 

해결방법 1

template<typename Company>
class LoggingMsgSender : public MsgSender<Company>
{
public:
	void SendClearMsg(const MsgInfo& info)
	{
		this->SendClear(info);
	}
};

 

this-> 를 사용해 SendClear 가 상속되었고, 실제로 들어온 인스턴스의 SendClear 를 사용하겠다 ! 고 선언한다

 

 

해결방법 2

using 을 사용한다. (항목 33과 관련)

클래스의 유효범위를 컴파일러에게 전달해준다

 

template<typename Company>
class LoggingMsgSender : public MsgSender<Company>
{
public:
	//컴파일러에게 MsgSender 안에 SendClear 를 확인하면 된다고 알려줌
	using MsgSender<Company>::SendClear;
	void SendClearMsg(const MsgInfo& info)
	{
		SendClear(info);
	}
};

 

 

해결방법 3

호출할 함수가 기본 클래스의 함수라는 것을 명시적으로 지정한다

template<typename Company>
class LoggingMsgSender : public MsgSender<Company>
{
public:
	void SendClearMsg(const MsgInfo& info)
	{
		MsgSender<Company>::SendClear(info);
	}
};

 

호출 함수가 가상 함수인 경우 가상 함수 바인딩이 무시된다

 

 

 

728x90
Comments