[C++] 다중상속한 클래스에서 다형성(폴리모피즘)을 사용 방법?

ssehoony의 이미지

class BASE_LEFT;
class BASE_RIGHT;
class DERIVED : public BASE_LEFT, public BASE_RIGHT;

DERIVED* child = new DERIVED();

BASE_LEFT* parent_left = (BASE_LEFT*)child;
BASE_RIGHT* parent_right = (BASE_RIGHT*)child;

위 와 같이 parent_left 와 parent_right 를 사용할 수 있나요?
부모 클래스(BASE_LEFT or BASE_RIGHT)로 캐스팅 될때 자식(DERIVED) 의 type 을 알고 있으니깐 가능할 법도 한데
그렇다면
class BASE_LEFT;
class BASE_RIGHT;
class DERIVED : public BASE_LEFT, public BASE_RIGHT;

DERIVED* child = new DERIVED();

BASE_LEFT* parent_left = (BASE_LEFT*)child;
BASE_RIGHT* parent_right = (BASE_RIGHT*)parent_left;

와 같은 상태에서는 parent_left 를 BASE_RIGHT* 로 타입캐스팅하면 문제가 될 듯 하네요.

다중상속한 클래스에 대한 다형성에 대한 전반적인 것을 알고 싶습니다.
다중상속시에는 다형성을 사용하지 않는 것이 좋은가요?

doldori의 이미지

devilhero wrote:
class BASE_LEFT;
class BASE_RIGHT;
class DERIVED : public BASE_LEFT, public BASE_RIGHT;

DERIVED* child = new DERIVED();

BASE_LEFT* parent_left = (BASE_LEFT*)child;
BASE_RIGHT* parent_right = (BASE_RIGHT*)child;

위 와 같이 parent_left 와 parent_right 를 사용할 수 있나요?
부모 클래스(BASE_LEFT or BASE_RIGHT)로 캐스팅 될때 자식(DERIVED) 의 type 을 알고 있으니깐 가능할 법도 한데

네, 됩니다. 이것은 자식 클래스의 포인터를 부모 클래스의 포인터로 변환할 수
있다는 것(upcasting)과 같은 이치입니다. 그리고 명시적인 캐스팅도 필요없습니다.

devilhero wrote:
그렇다면
class BASE_LEFT;
class BASE_RIGHT;
class DERIVED : public BASE_LEFT, public BASE_RIGHT;

DERIVED* child = new DERIVED();

BASE_LEFT* parent_left = (BASE_LEFT*)child;
BASE_RIGHT* parent_right = (BASE_RIGHT*)parent_left;

와 같은 상태에서는 parent_left 를 BASE_RIGHT* 로 타입캐스팅하면 문제가 될 듯 하네요.

이 경우에는 문제가 됩니다. 지금은 parent_left가 가리키는 개체가 실제로는
DERIVED임을 알고 있기 때문에 가상함수도 제대로 동작하겠지만, 실무에서
이런 식의 캐스팅을 쓰는 것은 매우 위험합니다. C도 그렇지만 특히 C++에서는
포인터의 명시적인 캐스팅은 코드에 치명적인 결함이 있음을 나타내는 증거라고
의심해도 됩니다.

devilhero wrote:
다중상속한 클래스에 대한 다형성에 대한 전반적인 것을 알고 싶습니다.
다중상속시에는 다형성을 사용하지 않는 것이 좋은가요?

그렇지 않습니다. 다중상속도 필요하면 얼마든지 사용할 수 있는 것입니다. 그런데
다중상속에서는 특히 조심해야 할 것들이 있기 때문에 쓰지 말라느니 하는 얘기가
나오는 겁니다. 전반적인 것은 여기서 얘기하기에는 너무 방대하므로 책을 보시는
것이 좋겠습니다. Effective C++이나 The C++ Programming Language에
잘 나와 있고, C++ FAQ Lite을 보셔도 잘 알 수 있을 것입니다.
ssehoony의 이미지

좋은 답변 감사합니다.
답변주신 자료를 통해 좀 더 공부해야겠네요.
좋은하루되세요.

blitzerg의 이미지

doldori wrote:
C도 그렇지만 특히 C++에서는
포인터의 명시적인 캐스팅은 코드에 치명적인 결함이 있음을 나타내는 증거라고
의심해도 됩니다.

저번에도 이런 내용의 토의가 이루어졌던 걸로 기억하는데 포인터의 명시적인 캐스팅이 코드에 치명적인 결함이 있음을 나타내는 증거라고 하는 이유는 어디에 있는지요? 계속된 토의에도 불구하고 계속 왜 이런 생각을 하시게되었는지 그 근거를 알고싶군요.
1970년대부터 출판된 프로그래밍 관련 서적이나 논문을 보시면(어쩌면 그 이전부터) 지속적으로 strong type의 필요성이나 타입 캐스팅의 필요성에 대해 언급하고 있습니다.
doldori님께서 경험 많고 친절한 프로그래머라는 사실은 기존의 많은 분량의 글로 인해 충분히 인정할 수 있습니다만 검증되지 않은 지식을 함부로 다른 분들에게 확산시키는건 잘못된 일이라고 지적하고 싶군요.
개인적인 경험에 의해 왜 그러한 생각을 하셨는지 공감은 합니다만 조금더 자료만 찾아보시면 금방 잘못된 지식이라는 것을 알 수 있으리라 생각합니다.
doldori의 이미지

정말 제가 근거없이 허황된 얘기를 한다고 생각하십니까? 제가 C++을 공부하면서
봤던 책, 아티클, 뉴스그룹의 포스팅은 일관되게 명시적인 캐스팅을 위험한 것으로
기술했습니다. 이전 쓰레드에서도 그 일부를 보여드렸습니다.

http://groups.google.co.kr/groups?selm=kbjo9.147%24t56.4603%40news.hananet.net
http://groups.google.co.kr/groups?selm=3ADD0E1D.FB9609C%40bawi.org
http://www.cinsk.org/cfaqs/html/node9.html#7.7

더 필요하신가요?

http://www.parashift.com/c++-faq-lite/coding-standards.html#faq-27.10

--

http://www.research.att.com/~bs/bs_faq2.html#void-ptr
"Casts are best avoided."

--

http://www.research.att.com/~bs/learn.html
"I consider most casts in C++ programs signs of poor design. Some
casts are essential, but most aren't. In my experience, old-time C
programmers using C++ and C++ programmers introduced to OOP
through Smalltalk are among the heaviest users of casts of the kind
that could have been avoided by more careful design."

--

http://www.artima.com/intv/elegance3.html
"Bjarne Stroustrup: Yes. That's the new cast syntax. Casts do provide
an essential service. The new syntax is an improvement over the C-style
casts because it allows the compiler to check for errors that it couldn't
with the old syntax. But the new syntax was made deliberately ugly,
because casting is still an ugly and often unsafe operation."

--

http://www.artima.com/intv/goldilocks.html
"And if you've got a lot of casts in the code, there's something wrong.
You have dropped from the level of types, a high level of abstraction,
down to a level of bits and bytes. You shouldn't do that very often."

--

More Effective C++, from Item 31:

// A bad idea...
SpaceShip::HitMap* SpaceShip::InitializeCollisionMap()
{
    HitMap* phm = new HitMap;

    (*phm)["SpaceShip"] = reinterpret_cast<HitFunctionPtr>(&hitSpaceShip);
    /* ... */
}

This will compile, but it's a bad idea. It entails someting you should
never do: lying to your compilers.

이외에도 comp.lang.c, comp.lang.c++, han.comp.lang.c, han.comp.lang.c++ 등
관련 뉴스그룹을 훑어보시면 명시적인 캐스팅을 가능한 한 피하라는 얘기는 수없이
많습니다.
저는 오히려 blitzerg님의 주장에 대한 근거를 알고 싶습니다. 만약 70년대의 문헌을
근거로 제 얘기를 검증되지 않은 얘기로 치부하신다면 그건 구식 스타일에 젖어있기
때문이라고 감히 말씀드릴 수 있습니다.

bugiii의 이미지

조금 날카로워질 위험이 있어서 주저주저 하다가 몇글자 남깁니다.

저는 doldori 님의 주장과 같은 내용이 맞다고 배웠고 그렇게 알고 있습니다만, blitzerg 님의 주장이 맞다면 이러이러해서 그렇다라고 자료를 제시해주시면 좋겠습니다. 제가 잘못 알고 있었다면 고쳐야 하겠지요. blitzerg 님께서 자신의 경험과 지식을 근거할 수 있는 자료를 미리 제시하셨으면 좋았을 것을 하는 생각이 들었습니다.

그리고, 다른 사람의 주장을 반박할 때는 좀 더 완곡한 표현을 사용하셨으면 좋겠습니다. "검증되지 않은 지식을 함부로" 라든가 "금방 잘못된 지식이라는" 것 같은 표현은 상대방에게 상당한 상처를 줄 수도 있다고 봅니다.

어떤 사실을 단정 짓는 표현이 얼마나 위험하고 조심스러운 것인지 경험을 통해서 잘 알고 있는터라 글을 쓸 때 한번더 생각하고, 글을 쓰고나서도 백버튼을 누른 경우가 많습니다.

서로에게 좀 더 정확하고 좋은 정보를 공유할 수 있는 게시판 분위기가 잘 유지되었으면 좋겠습니다.

p.s. 괜히 참견해서 분란만 일으키는 행동이 아니길 빕니다...

p.s. doldori 님의 의도는 가능한한 사용하지 말자라고 이해하고 있습니다. 사용해야 하는 경우는 분명히 있긴 하니까요. blitzerg 님께서도 절대 사용하지 말아야 한다는 것의 반론이라면 이정도 수준에서 서로 이해가 되었으면 좋겠습니다.

익명 사용자의 이미지

Quote:
C도 그렇지만 특히 C++에서는
포인터의 명시적인 캐스팅은 코드에 치명적인 결함이 있음을 나타내는 증거라고 의심해도 됩니다.

이 문장이 아래의 code에 국한된 이야기가 아니라면도 조금 도발적이군요. 99(?)%는 결함이 없는것 같던데요.

Quote:
class BASE_LEFT;
class BASE_RIGHT;
class DERIVED : public BASE_LEFT, public BASE_RIGHT;

DERIVED* child = new DERIVED();

BASE_LEFT* parent_left = (BASE_LEFT*)child;
BASE_RIGHT* parent_right = (BASE_RIGHT*) parent_left;


이러한 캐스팅은 상당히 극단적인 형태 같아 보이네요.

p.s 캐스팅을 너무 몰아 붙이지 마세요 :)

blitzerg의 이미지

bugiii님의 글을 보고 말씀드립니다.

그런 걱정을 끼쳐드린데 대해서 죄송하다고 말씀드리고 싶습니다.

사실 글을 남겼으나 그에 대한 자료를 올리기에는 그 시간이 너무 소요되는 관계로 올릴 수가 없습니다.

이에 대해서 doldori님께도 죄송합니다.

기억에 가물가물하는 자료들을 찾아보려니 엄두가 안나는 군요.

지금도 중요한 업무를 수행중이라 다음에 시간이 나면 그에 대한 자료를 올리도록 하겠습니다.

저 또한 업무상 C++를 사용하고 있는 입장이라 지적하시는 부분이 무엇인지 제대로 파악하고 있습니다.

그러한 부분은 맞으나 제가 지적하고 싶은 부분은 캐스팅이 "치명적인 결함"이라고 주장하시는 부분에 대해서 인데...

왠지 bugiii님 말씀을 보고 곰곰히 생각해보니 말꼬리잡고 싸움을 거는 기분이라 여기서는 제가 조용히 수긍하고 덮어두겠습니다.

증거자료를 가지고 조만간 찾아뵙겠습니다.

doldori의 이미지

alsong~ wrote:
Quote:
C도 그렇지만 특히 C++에서는
포인터의 명시적인 캐스팅은 코드에 치명적인 결함이 있음을 나타내는 증거라고 의심해도 됩니다.

이 문장이 아래의 code에 국한된 이야기가 아니라면도 조금 도발적이군요. 99(?)%는 결함이 없는것 같던데요.


저는 이것을 도발적이라고 받아들이시는 것이 더 의외입니다. C++ 커뮤니티에서는
별로 새로울 것도 없는 상식적인 얘기입니다. 여기저기 캐스팅을 쓴 코드라도 지금
당장은 돌아가게 할 수 있을지도 모릅니다. 더 큰 문제는 장기적인 유지보수입니다.
저는 그런 코드를 유지보수할 자신이 없군요.

alsong~ wrote:

Quote:
class BASE_LEFT;
class BASE_RIGHT;
class DERIVED : public BASE_LEFT, public BASE_RIGHT;

DERIVED* child = new DERIVED();

BASE_LEFT* parent_left = (BASE_LEFT*)child;
BASE_RIGHT* parent_right = (BASE_RIGHT*) parent_left;


이러한 캐스팅은 상당히 극단적인 형태 같아 보이네요.

코드가 짧아서 잘못된 부분을 금방 알아볼 수 있을 뿐입니다. 수십만 라인의 소스
코드 내에 저런 것이 들어가 있다면 어떨 거라고 생각하십니까? 이런 극단적인
캐스팅을 바로 잡아낼 자신이 있으십니까? 애당초부터 이런 코드는 작성하지
않을 거라고 생각하실지는 몰라도, 제 경험상 대부분의 버그는 정말로 바보같은
실수 때문이었습니다. 캐스팅을 쓰지 않았다면 컴파일러의 메시지로 알아낼 수
있는 오류를 그냥 덮어버린 식이었죠.
캐스팅은 너무 남용되는 경향이 있습니다. 심지어는 오류가 있는 코드를 컴파일이라도
성공하기 위해 캐스팅을 쓰는 것도 봤습니다. Stroustrup은 캐스팅의 폐해를 너무나
잘 알고 있었기에 C++ 스타일의 캐스팅 문법을 도입했고 그마저도 보기 흉하게
만들어 가능한 한 쓰지 말라는 의도를 분명히 했습니다. (그런데 그것이 역효과를
내서 C 스타일의 캐스트를 그냥 쓰는 사람도 있더군요. :( ) C++은 캐스팅 없이도
코드를 작성할 수 있도록 여러 장치들이 마련되어 있습니다.
doldori의 이미지

blitzerg wrote:
bugiii님의 글을 보고 말씀드립니다.

그런 걱정을 끼쳐드린데 대해서 죄송하다고 말씀드리고 싶습니다.

사실 글을 남겼으나 그에 대한 자료를 올리기에는 그 시간이 너무 소요되는 관계로 올릴 수가 없습니다.

이에 대해서 doldori님께도 죄송합니다.

기억에 가물가물하는 자료들을 찾아보려니 엄두가 안나는 군요.

지금도 중요한 업무를 수행중이라 다음에 시간이 나면 그에 대한 자료를 올리도록 하겠습니다.

저 또한 업무상 C++를 사용하고 있는 입장이라 지적하시는 부분이 무엇인지 제대로 파악하고 있습니다.

그러한 부분은 맞으나 제가 지적하고 싶은 부분은 캐스팅이 "치명적인 결함"이라고 주장하시는 부분에 대해서 인데...

왠지 bugiii님 말씀을 보고 곰곰히 생각해보니 말꼬리잡고 싸움을 거는 기분이라 여기서는 제가 조용히 수긍하고 덮어두겠습니다.

증거자료를 가지고 조만간 찾아뵙겠습니다.


알겠습니다. 기대하겠습니다.
익명 사용자의 이미지

치명적인 결함에 의미를 생각하기 보다는
어떨때 사용하고 어떨땐 사용하지 말하야 하는가를 알고 넘어가는게 좋은것 같습니다.

님 덕분에 캐스팅의 문제점을 알게 됐습니다. 그 중한가진 격었던 적이 있었네요 :)

corba의 이미지

적어도 클래스의 포인터를 사용 시 캐스팅이 들어 가야 했던 경우는 항상 제 설계에 문제가 있었던 경우 같습니다 :->

atie의 이미지

두번째 예시되어 있는 코드를 "캐스팅"이라고 하는 것은 상속 계층을 감안하면, 제 생각에는 어불성설이라 봅니다.

----
I paint objects as I think them, not as I see them.
atie's minipage

mastercho의 이미지

blitzerg wrote:
doldori wrote:
C도 그렇지만 특히 C++에서는
포인터의 명시적인 캐스팅은 코드에 치명적인 결함이 있음을 나타내는 증거라고
의심해도 됩니다.

저번에도 이런 내용의 토의가 이루어졌던 걸로 기억하는데 포인터의 명시적인 캐스팅이 코드에 치명적인 결함이 있음을 나타내는 증거라고 하는 이유는 어디에 있는지요? 계속된 토의에도 불구하고 계속 왜 이런 생각을 하시게되었는지 그 근거를 알고싶군요.
1970년대부터 출판된 프로그래밍 관련 서적이나 논문을 보시면(어쩌면 그 이전부터) 지속적으로 strong type의 필요성이나 타입 캐스팅의 필요성에 대해 언급하고 있습니다.
doldori님께서 경험 많고 친절한 프로그래머라는 사실은 기존의 많은 분량의 글로 인해 충분히 인정할 수 있습니다만 검증되지 않은 지식을 함부로 다른 분들에게 확산시키는건 잘못된 일이라고 지적하고 싶군요.
개인적인 경험에 의해 왜 그러한 생각을 하셨는지 공감은 합니다만 조금더 자료만 찾아보시면 금방 잘못된 지식이라는 것을 알 수 있으리라 생각합니다.

일반적으로
사용시 부모 포인터에 자식 포인터를 대입할때는 타입 케스팅이 필요 없습니다

그런데 케스팅을 썼다는것은
코드 로직상으로 강제로 형을 변환해야 했었다는 의미를 남길수 있는것이죠

일반적으로 이러한 강제 형변환은 , 잘못된 설계로 부터 비롯될수 있는데

부모 포인터를 자식 포인터에 강제 케스팅해서 써야 할때나 주로 그렇게 사용했던걸로 기억되네요

어째튼 ....제가 판단하기에는
당장 프로그램에는 이상은 없겠으나 저런 코드가 나중 유지보수할때 애매함을 남길수 있기때문에 결함을 유발할수 있는 코드도 될수 있다 라고 봐도 되지 않을까 싶습니다

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.