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

Minsu._.Lighting·2023년 12월 12일
0

[ Effective C++ ] 정리 모음집
" C++ 프로그래머의 필독서, 스콧 마이어스의 Effective C++ 를 읽고 내용 요약 / 정리 "

[핵심]

" 기본 클래스의 멤버에 대한 참조가 무효한지를 컴파일러가 진단하는 과정이 미리 들어가느냐, 나중에 들어가느냐가 이번 항목의 핵심! C++은 이른 진단을 선호하는 정책을 결정! "

  • 파생 클래스 템플릿에서 기본 클래스 템플릿의 이름을 참조할 때는, "this->"를 접두사로 붙이거나 기본 클래스 한정문을 명시적으로 써 주는 것으로 해결하자!

💡 템플릿으로 만들어진 기본 클래스

class CompanyZ
{
public:
	...
    void sendEncrypted(const string& mgs);
    ...
};

[CompanZ 를 위한 MsgSender의 특수화 버전]
template<>
class MsgSender<CompanyZ>
{
public:
	...
    void sendSecret(const MsgInfo& info)
    { ... }
};

template<typename Company>
class LoggingMasgSender : public MsgSender<Company>
{
public:
	...
    void sendClearMsg(const MsgInfo& info)
    {
    	"메세지 전송 전" 정보를 로그에 기록
        
        sendClear(info);
        
        "메세지 전송 후" 정보를 로그에 기록
    }
    ...
};
  • 위 코드는 기본 클래스가 MsgSender<CompanyZ>이면 말이 되지 않는 코드이다
    - MsgSender<CompanyZ> 클래스에는 sendClear 함수가 없으므로..
    - 이런 일이 생길 수 있어 위와 같은 함수 호출을 C++에서는 막아 놓음
    - 기본 클래스 템플릿은 언제라도 특수화될 수 있고, 이런 특수화 버전에서 제공하는 인터페이스가 원래의 일반형 템플릿과 꼭 같으리란 법은 없다는 점을 C++가 인식한다는 이야기!

📢 위와 같은 이유로 C++ 컴파일러는 템플릿으로 만들어진 기본 클래스를 뒤져서 상속된 이름을 찾는 것을 거부한다!

📌 해결 방법 1 - "this->"

template<typename Company>
class LoggingMsgSender : public MsgSender<Company>
{
public:
	...
    void sendClearMsg(const MsgInfo& info)
    {
    	"메세지 전송 전" 정보를 로그에 기록
        
        this->sendClear(info);
        
        "메세지 전송 후" 정보를 로그에 기록
    }
    ...
};
  • 기본 클래스 함수에 대한 호출문 앞에 "this->"를 붙인다!
    this->sendClear(info);
    - sendClaer가 상속되는 것으로 가정한다.

📌 해결 방법 2 - "using 선언"

template<typename Company>
class LoggingMsgSender : public MsgSender<Company>
{
public:
	...
    using MsgSender<Company>::sendClear;
    ...
    
    void sendClearMsg(const MsgInfo& info)
    {
    	"메세지 전송 전" 정보를 로그에 기록
        
        sendClear(info);
        
        "메세지 전송 후" 정보를 로그에 기록
    }
    ...
};
  • suing 선언을 사용해 기본 클래스의 이름을 파생 클래스의 유효범위로 끌어온다.
    using MsgSender<Company>::sendClear;
    - sendClaer가 상속되는 것으로 가정한다.

📌 해결 방법 3 - "호출할 함수가 기본 클래스의 함수라는 점을 명시적으로 지정"

template<typename Company>
class LoggingMsgSender : public MsgSender<Company>
{
public:
	...
    void sendClearMsg(const MsgInfo& info)
    {
    	"메세지 전송 전" 정보를 로그에 기록
        
        MsgSender<Company>::sendClear(info);
        
        "메세지 전송 후" 정보를 로그에 기록
    }
    ...
};
  • 해당 방법은 문제 해결에 있어 추천하고 싶지 않다!
    MsgSender<Company>::sendClear(info);
    - 호출되는 함수가 가상 함수인 경우, 명시적 한정을 해 버리면 가상 함수 바인딩이 무시되기 때문!

📌 주의할 점

LoggingMsgSender<CompanyZ> zMsgSender;
MsgInfo msgData;
...									// msgData에 정보를 채운다
zMsgSender.sendClearMsg(msgData);	// 컴파일 되지 않는다, 에러!
  • 기본 클래스가 MsgSender<CompanyZ>라는 사실을 컴파일러가 알고 있음

  • sendClearMsg함수가 호출하려고 하는 sendclear 함수는 MsgSender<CompanyZ>클래스에 안 들어 있다는 사실도 컴파일러가 알아챈 후 이기 때문..

profile
오코완~😤😤

0개의 댓글

관련 채용 정보