[ [Mistakable Codes - #4] 연산자 오로딩 시 주의 사항. operator<< operator overloading, error C2666: ‘<<‘ : 13 overloads have similar conversions
Dec 05
Programming/C/C plus plus c++, c/c++, Mistakable Codes, overloading, Programming, Tips&Tricks 8 Comments
근래 (약 1주일 동안) 이런저런 결정할 일들과 알아볼 일이 있어서 블로깅을 거의 못했습니다.
아무튼, 오늘은 간과하기 쉬운 실수에 대해서 포스팅을 합니다.
(이와 관련되어서는 언제 한 번 포스팅하겠습니다. ^^;; 지극히 사적인 부분이기는 하나)
다음 코드는 간단히 CTest라는 class를 만들어서 std::ostringstream::operator<<를 overloading했습니다.
즉, CTest를 operator<<가 인자로 받을 때 int 멤버 변수인 m_nNum을 operator<<에 넘겨주는 코드입니다.
#include <iostream>
#include <sstream>
class CTest
{
private:
int m_nNum;
public:
CTest(int n = 0)
{
m_nNum = n;
};
// operator<< overriding
// 이 부분은 꼭 friend로 하지 않고 일반 함수로 만들어도 되겠죠.
friend std::ostringstream& operator<<(std::ostringstream& outstream, const CTest& t)
{
outstream<<t.m_nNum;
return outstream;
}
int GetNum() { return m_nNum;};
};
void main()
{
CTest t(3);
std::ostringstream str;
// operator<< overriding 사용
str<<t; //<———– (1)
std::cout<<str.str()<<std::endl;
}
하지만 위 코드를 컴파일 하면 아래와 같은 에러 메시지를 만나게 됩니다.
error C2666: ‘<<’ : 13 overloads have similar conversions
말그대로 operator<<를 overloading한 것중 어느 것을 선택해야 할지 모르겠다는 것입니다.
즉, (1)에서 컴파일러는 13개의 overloading 된 함수 후보 중 어떤 것을 사용할지 모르겠다는 것입니다.
해결책 – 1
간단하게 컴파일러에게 매개 변수로 int를 받으면 CTest의 생성자를 써라고 명시적으로 지정해주는 것입니다. 즉, explicit 키워드를 사용하는 것입니다.
※ CTest의 생성자를 int에 대해서 명시적으로 사용하게 정의하는 것으로 볼 수 있겠죠.
explicit CTest(int n = 0)
{
m_nNum = n;
};
해결책 -2
하지만 explicit를 사용하면 다음과 같이 컴파일러가 알아서 디폴트 생성자를 불러주는 호화스러운 기능은 사용할 수 없습니다.
void main()
{
A a = 1; //const int를 class A로 변환할 수 없습니다.
// 즉, const int를 A(int)로 변환할 수 없습니다.
}
이런 부분을 고려해서, 아래와 같이 디폴트 생성자를 따로 만들어주고 CTest(int)의 디폴트 값을 제거할 수도 있습니다.
gimmesilver 님이 지적해주신 것 처럼 아래 코드 처럼 디폴트 생성자를 작성한다고 해서 A a =1;과 같은 코드가 가능해지는 것은 아닙니다.
디폴트 생성자가 필요한 다른 부분 (즉, CTest(int a =0); 으로 하면 디폴트 생성자가 굳이 없어도 되지만)을 위한 것이라고 보시면 됩니다.)
// 디폴트 복사 생성자
CTest(){};
// int에 대한 생성자
explicit CTest(int n)
{
m_nNum = n;
};
Ref: comp.lang.c++ Is it VC++ or I am going crazy???
^^ 그리고 gimmesilver님의 마지막 지적 처럼 위 코드의 옳고 그름의 가치를 떠나 Legacy나 가져다 쓰고 있는 오픈 소스에서 발생했을 경우 때문에 포스팅을 합니다.
