Home // Blog
Home // Notice
Home // Tag Log
Home // Location Log
Home // Media Log
Home // GuestBook
C++이야기 스물네번째: Override할 가상함수의 Prototype은 확인 또 확인!
Posted at 2008. 10. 31. 00:46 //
in S/W개발/C++ 이야기 //
by
이번에는 C++로 프로그래밍하다가 저지르기 쉬운 실수에 대해 한 번 말씀드리겠습니다. 가상함수 관련된 실수입니다. 여러 말보다는 한 줄 코딩이 낫다고 우선 코드부터 보시죠.
#include <iostream>
#include <string>
using namespace std;
class Base
{
public:
virtual void hello(const string& name)
{
cout << "Don't call Base::hello(" << name << ")" << endl;
}
};
class Derived : public Base
{
public:
virtual void hello(const string name)
{
cout << "Hello, " << name << "!" << endl;
}
};
int
main()
{
Base* p = new Derived();
p->hello("KKK");
}
코드 잘 보셨죠? 자~ 그럼 퀴즈 들어갑니다. 위 코드를 컴파일해서 실행하면 어떤 결과가 나올까요? 엇! 이런 것도 퀴즈라고 날 어떻게 보고 하시면서 눈을 부라리는 분이 계시군요. 오늘 퀴즈는 그런분들을 위해 내는 것이니 절 보고 눈 부라리시지 마시고, 코드를 다시 한 번 보시기 바랍니다. 어떠세요? 이런 결과가 나올 것이라고 예상하셨나요?
Hello, KKK!
앗! 그런데 어떡하죠? 제 컴퓨터에서는 이렇게 나오네요.
Don't call Base::hello(KKK)
이게 무슨 조화죠? p 가 Base* 형이긴 하지만 Derived()를 생성했으니까 당연히 "Hello, KKK!"라고 찍혀야 하는 거 아닌가? 정 저를 못 믿으시겠다면 직접 한 번 컴파일하시고 실행해 보세요~ 어때요? 제 말이 맞죠? ㅋㅋㅋ
다시 퀴즈 들어갑니다. 그렇다면 왜 이런 결과가 발생하는 걸까요?
일
이
삼
사
오
육
칠
팔
구
십! 삐~
시간 초과되셨습니다.
다시 한 번 코드를 자세히 들여다 보겠습니다.
class Base
{
public:
virtual void hello(const string& name) { ...... }
};
class Derived : public Base
{
public:
virtual void hello(const string name) { ...... }
};
빨갛게 표시한 부분의 차이점이 보이시나요? 그렇습니다. 단지 '&'가 빠져있을 뿐입니다. C++ 컴파일러가 가상함수의 override 여부를 판단할 때는 함수 인자가 정확히 일치될 경우에만 override 된 것으로 판단합니다. 위 경우에는 hello member function이 override된 것이 아니라 overload된 경우가 될 것입니다. 즉, 별개의 멤버 함수인 것이죠. 따라서 Base* 형인 p에 대해 hello()를 호출하면 원래의 Base::hello() 가 호출되어 버리는 것입니다.
이 예는 비교적 간단한 예라서 비교적 찾기 쉽지 실제 프로그램이 복잡해지면 이런 에러는 정말 찾기가 힘듭니다. 그러니 코드 리뷰하면서 미리 미리 가상함수 상속받아서 override하면서 함수 Prototype을 일치시켰는지 꼭 확인에 확인해 보시기 바랍니다. 저도 얼마전에 이 문제 때문에 한참을 헤맸답니다.ㅠ.ㅠ
이제 마무리 들어갑니다. 가상함수를 쓰실 때는 다음 주의사항을 꼭 명심하시기 바랍니다.
"Override할 가상함수의 Prototype은 확인 또 확인하자"
#include <iostream>
#include <string>
using namespace std;
class Base
{
public:
virtual void hello(const string& name)
{
cout << "Don't call Base::hello(" << name << ")" << endl;
}
};
class Derived : public Base
{
public:
virtual void hello(const string name)
{
cout << "Hello, " << name << "!" << endl;
}
};
int
main()
{
Base* p = new Derived();
p->hello("KKK");
}
코드 잘 보셨죠? 자~ 그럼 퀴즈 들어갑니다. 위 코드를 컴파일해서 실행하면 어떤 결과가 나올까요? 엇! 이런 것도 퀴즈라고 날 어떻게 보고 하시면서 눈을 부라리는 분이 계시군요. 오늘 퀴즈는 그런분들을 위해 내는 것이니 절 보고 눈 부라리시지 마시고, 코드를 다시 한 번 보시기 바랍니다. 어떠세요? 이런 결과가 나올 것이라고 예상하셨나요?
Hello, KKK!
앗! 그런데 어떡하죠? 제 컴퓨터에서는 이렇게 나오네요.
Don't call Base::hello(KKK)
이게 무슨 조화죠? p 가 Base* 형이긴 하지만 Derived()를 생성했으니까 당연히 "Hello, KKK!"라고 찍혀야 하는 거 아닌가? 정 저를 못 믿으시겠다면 직접 한 번 컴파일하시고 실행해 보세요~ 어때요? 제 말이 맞죠? ㅋㅋㅋ
다시 퀴즈 들어갑니다. 그렇다면 왜 이런 결과가 발생하는 걸까요?
일
이
삼
사
오
육
칠
팔
구
십! 삐~
시간 초과되셨습니다.
다시 한 번 코드를 자세히 들여다 보겠습니다.
class Base
{
public:
virtual void hello(const string& name) { ...... }
};
class Derived : public Base
{
public:
virtual void hello(const string name) { ...... }
};
빨갛게 표시한 부분의 차이점이 보이시나요? 그렇습니다. 단지 '&'가 빠져있을 뿐입니다. C++ 컴파일러가 가상함수의 override 여부를 판단할 때는 함수 인자가 정확히 일치될 경우에만 override 된 것으로 판단합니다. 위 경우에는 hello member function이 override된 것이 아니라 overload된 경우가 될 것입니다. 즉, 별개의 멤버 함수인 것이죠. 따라서 Base* 형인 p에 대해 hello()를 호출하면 원래의 Base::hello() 가 호출되어 버리는 것입니다.
이 예는 비교적 간단한 예라서 비교적 찾기 쉽지 실제 프로그램이 복잡해지면 이런 에러는 정말 찾기가 힘듭니다. 그러니 코드 리뷰하면서 미리 미리 가상함수 상속받아서 override하면서 함수 Prototype을 일치시켰는지 꼭 확인에 확인해 보시기 바랍니다. 저도 얼마전에 이 문제 때문에 한참을 헤맸답니다.ㅠ.ㅠ
이제 마무리 들어갑니다. 가상함수를 쓰실 때는 다음 주의사항을 꼭 명심하시기 바랍니다.
"Override할 가상함수의 Prototype은 확인 또 확인하자"