[완료] C++에 대해, 부모클래스와 멤버함수만 추가한 자식클래스간의 변환에 대해서
글쓴이: klara / 작성시간: 일, 2009/04/26 - 4:26오전
class A { public: A(int value):v(value) {} int value() const {return v;} private: int v; }; class B : public A { public: B():A(0) {} bool isZero() const {return value() == 0;} };
위와 같은 코드가 있습니다. B는 A를 상속받되, 새로운 멤버변수는 추가하지 않고 멤버함수만을 추가하였습니다.
이때,
A a(1); B &b = static_cast<B&>(a); if (b.isZero()) { ... }
위와 같은 코드는 안전한 코드일까요?
특히 클래스 A의 경우 소멸자가 비가상함수인데요, B에서는 멤버변수 추가가 없으므로,
A *a = new B; delete a;
와 같이 하여도 메모리누수의 걱정도 없을 듯한데, 무언가 문제되는 것이 있을까요?
Forums:
원하시는 대답은 아니겠지만
딱히 흥미가 아닌 이상 이렇게 하는 이유는 없을 거 같고요.
A, B 모두 가상 멤버 함수가 없느니만큼 실제적으로는 문제가 발생하지는 않겠지만 그렇더라도 표준에서는 이런 부분에 대해서 언급을 하지 않거나 언급한다면 비정의 동작이라고 할 것 같아요.
제 실력이 부족한
제 실력이 부족한 탓인지 모르겠지만, '흥미'외에 실제로도 사용하게 되는 경우가 있었습니다.
STL의 클래스들 처럼 부모 클래스가 제가 만든 클래스가 아니라 사용하는 라이브러리에서 제공하는 클래스이고, 상속을 염두에 두지 않았을 경우입니다.
좀더 구체적인 예를 들어 보면...
여기서 namespace Lib 는 외부 라이브러리이기 때문에 제가 수정할수가 없을때, Data 클래스를 확장하고 싶은 경우,
와 같이 선언하여
와 같이 이용하고 싶은 경우입니다.
물론 이를 해결하기 위해서 상속하지 않고 다른 방법이 있다는 것을 알고 있습니다만, 실제로 MyData는 Lib::Data 그자체이므로, 예를 들어 MyData에 멤버변수로 Data를 선언하여 Data MyData::data() const 와 같은 멤버함수로 접근하게 하는 것은 번거롭기도하고 실제로 의미상으로도 적합하지 않아 보입니다.
실력은 제가 부족하지요.
우선 제가 말씀드릴 수 있는 것은 C++ 언어는 이런 방식을 받아들이지 않는다는 것입니다.
비슷한 예로 STL의 string의 경우 상속될 여지가 많음에도 표준화 위원회가 가상소멸자를 넣지 않은 것은 고심 끝에 이루어진 것으로 알고 있습니다.
원래 Data를 만든 분이 어디까지 고민을 하셨을런지 모르지만 만일 C++ 언어의 방식을 받아들이고, Data를 만드신 분을 존중한다면 다른 방식이 적합하다고 봅니다. 만일 자신이 표현하고자 하는 방식이 그 이상의 가치를 지닌다면 적절히 실험 후에 임의로 변경할 수 있겠지요. 언제나 표준이나 기본 library 설계자의 의견이 옳은 것도 아니고, 그들이 생각하지 못하는 바도 생길 수 있으니까요. 하지만 이것이 단지 여기서 통용되는 기술이고, 다양하게 사용되는 형태의 기술이 아니라면 C++ 구현과 Data의 변화에 따라 같이 맞춰주는 것을 감내하셔야 합니다. 만일 다양하게 통용될 수 있는 기술이라면 새롭게 C++ 표준에 넣고자 제안을 할 수도 있고, Data 설계자와 협의를 할 수도 있겠지만 말이죠. 제가 보기에 그정도 의미를 담고 있지는 않아 보입니다.
제가 추천하는 바는 멤버변수의 추가가 없으므로 파생클래스를 만들지 말고 적절한 전역함수를 만들어서 쓰는 것이 어떨까 싶습니다. 파생클래스를 만들어 놓고, 기반클래스를 파생클래스로, downcasting을 그것도 적합하지 않은 방식으로 해야 한다는 것 자체가 객체지향에 어긋나는 부자연스러운 구조라고 봅니다.
지금 당장의 문제는 없겠습니다만,
해당 외부 라이브러리의 클래스의 소멸자가 비가상함수인 것은 기본적으로 상속해서 쓰지 말라는 선언이라고 생각합니다.
말씀하신 바와 같이, 다른 가상 함수도 없고 상속 받은 클래스에 멤버도 없기 때문에, 현재 본인이 쓰시는 경우에는 문제가 없을 수 있겠습니다만, 혹시 이 코드를 사용하게 되는 다른 개발자의 경우는 별 생각 없이 멤버 변수를 추가하거나, 혹은 이를 다시 상속 받아서 쓰거나 하는 과정에서 여러 문제를 발생시킬 여지가 아주 높다고 생각합니다. (다른 개발자의 범주에는 어느 정도 시간이 지난 후에, 이런 내용을 잊어 버린 미래의 본인도 포함될 수 있을 겁니다.)
아주 임시로 테스트하는 용도 이외에 정식으로 사용하는 코드에서는 이와 같은 방법을 사용하지 않는 것이 여러 모로 좋을 것이라고 생각합니다. (만약 제가 같이 일하는 동료가 이런 방법을 쓴다면 한대 쥐어 박아서라도 못 쓰게 할 것 같습니다. ^^)
이 질문은...
라는 질문과 똑같은 느낌을 줍니다.
예전에 제가 했던 질문이군요.
아마 이건 C++ 표준에 어긋나지는 않을 것 같기는 한데... 역시 쓸데없는 고민이었죠.
일단 표준에서는
일단 표준에서는 결과를 정의하지 않습니다.
멤버 변수는 추가가 안된 상황이지만 가상함수테이블, RTTI 혹은 컴파일러 구현자가 몰래 넣은 무언가가 메모리 누수보다 더 무서운 폭탄이 될 가능성이 있습니다.
이런 것 들을 처리하기 위해 소멸자에 보이지 않는 코드가 삽입된다는 것은 이미 아시리라 생각합니다.
:)
STL을 상속받아 쓰지
STL을 상속받아 쓰지 말아라 라고 누군가 말한것 같은데...
누군지 모르겠군요.^^
-----------------------
과거를 알고 싶거든 오늘의 네 모습을 보아라. 그것이 과거의 너니라.
그리고 내일을 알고 싶으냐?
그러면 오늘의 너를 보아라. 그것이 바로 미래의 너니라.
고작 블로킹 하나, 고작 25점 중에 1점, 고작 부활동
"만약 그 순간이 온다면 그때가 네가 배구에 빠지는 순간이야"
답변주신분들 모두
답변주신분들 모두 감사드립니다.
결국 다른 이유때문에라도 저런 변태적인 형변환은 하지 않고 다른 방법을 이용하게 되었습니다.
전역함수에 대해서도 생각해보았지만, 단순히 '전역함수가 싫다'는 이유때문에 안쓰고 있었는데, 다음에 또 비슷한 경우가 생기면 전역함수나 래핑 클래스를 이용하도록 해야겠습니다.
댓글 달기