C++ Labyrinth #1

(이 글은 2007년 1월 16일에 DokuWiki 에서 작성된 http://j.strane.net/dokuwiki/blog/2007/c_labyrinth_1 를 WordPress 로 옮긴 것입니다.)

Code

#include <iostream>
#include <string>
using namespace std;

class A
{
public:
    A () {};

    operator string() { return "It's A!"; };
};

class B
{
public:
    B () {};
    B (const A& temp) {};

    operator string() { return "It's B!"; };
};

int main()
{
    A a;
    B b;
    string sTemp = (true ? a : b);

    cout << "What do you expect?" << endl;
    cout << "Unfortunately, " << sTemp << endl;

    return 0;
}

Question

위 코드를 실행했을 때 예상되는 출력 결과는 무엇일까요?

  1. 위 코드는 gcc 3.3.5 에서 -Wall 옵션으로 워닝이나 에러없이 컴파일됩니다.
  2. 리플에 정답이나 힌트가 올라올 수 있습니다. 여기까지 읽으셨다면 문제에 필요한 내용은 다 읽으신 것이니 곰곰이 생각해보시거나 컴파일하고 돌려보신 후에 더 읽기를 눌러주세요.

Answer

정답은 여기에 숨겨져 있습니다. ▼

C++ 표준을 살펴봐야 좀 더 정확한 설명을 해드릴 수 있겠지만 우선 제가 아는 범위 내에서는 아래와 같이 설명할 수 있을 것 같습니다.

일단 C 계열은 strong-typed language 이므로 삼항 연산자의 결과값의 타입은 컴파일 타임에 결정이 되어야 합니다. 즉, (cond ? a : b) 가 있다면 이 연산자의 결과값이 무슨 타입인지를 컴파일 타임에 알아야 타입 체크를 해서 컴파일 에러를 내야할지 말지를 알 수 있겠죠. 그렇기 때문에 컴파일러는 (cond ? a : b) 에서 a 와 b 의 타입이 서로 다르면 a 와 b 의 타입을 같게 맞춰서 런타임에 cond 가 어떤 값을 가지더라도 동일한 타입을 리턴한다는 걸 보장하려고 합니다.

위 코드는 class A 타입에서 class B 타입으로 implicit conversion 이 가능하므로 컴파일러가 삼항 연산자의 결과값의 타입을 class B 라고 결정합니다. 따라서 class A 타입의 인스턴스가 리턴되는 경우에는 자동으로 class B 타입으로 변환이 되어서 나오게 되고 그래서 위와 같은 실행 결과가 나옵니다. 하지만 컴파일러가 행할 수 있는 implicit conversion 은 최대 한번까지만 가능하므로 한단계를 더 두어서 class C 까지 만들어서 짜면 아마 에러가 날 것 같습니다.

Related posts

  1. STL 을 믿지 마세요. – std::string 의 find()

Tags: , ,

  • http://digitz.tistory.com 디지츠

    예상하지 못했는데 저렇게 나오는군요.
    역시 삼항연산자에서 캐스팅 연산보다는 복사생성자를 먼저 따지는군요.

    후후후 많은걸 배워갑니다 ~

  • http://j.strane.net J.Strane

    디지츠// 정답 밑에 설명을 추가했습니다. 참고해주세요~

  • http://digitz.tistory.com 디지츠

    확실히 class C를 만들고 B&로 암시적 변환이 가능하게 해두어도
    컴파일 에러가 납니다. ( MSVC 8.0 )

    또한, A라는 기본 클래스에 A로 변환 가능한 B와 C를 만든 다음
    B와 C를 삼항 연산자로 묶어도 변환이 되지 않는군요.

    삼항 연산자 내부에서 암시적 변환은 모든 항에서 단 한번만 허용이 되는 것이군요.

  • Pingback: Codex praptor