C++ 최대 조상님을 몇대까지 두시나요?

ikpil의 이미지

상속에 관한 것인데요.

질문을 올리고도 질문이 참 광범위 하다고 생각됩니다.

1. 1대 부모님까지
2. 2대 조부님까지
3. 3대 증조부님까지
4. 4대 고조부님까지

.. 그 이유는 어디에 두시나요?

다중 상속은 몇개까지 허용 하시나요? (기본이 1개)
1. 2개까지
2. 3개까지
3. 4개까지

.. 그 이유는 어디에 두시나요?

개인적으로 사람을 만들때
간, 폐, 심장, 뇌 등을 클래스로 만들어서
Person : public 간, 폐 심장 뇌 .... 이렇게 생각해보았습니다.
이런건 신의 영역인가요? 2개 이상부턴 너무 복잡해집니다. ^^

klara의 이미지

특별한 제한은 없습니다.
그보다 Person클래스에 대한 설계로, 간이나 폐등의 장기를 public 상속을 받는데 이건 일반적으로 올바른 선택이 아닙니다.
보통 A가 B를 public 상속받는 경우, 'A는 B다(A is B)'라는 관계에 있습니다.
예를 들어 이동기구를 상속받는 자동차 클래스는, '자동차는 이동기구이다'라는 관계가 성립합니다.
그리고 private상속의 경우는 'A는 B를 가지고 있다(A has B)'의 관계에 있습니다.
사람의 경우, '사람은 폐이다'라는 건 말이 안됩니다만, '사람은 폐를 가지고 있다'라는 관계가 성립하므로, 이경우는 상속으로 해결하려한다면 public이 아닌 private상속을 쓰는게 일반적으로는 바람직합니다.
어째서 public은 A is B이고, private는 A has B인지에 대해서는 상속에 관한 내용을 찾아보시면 자세히 나올 것같습니다.

ikpil의 이미지

명쾌하십니다!
지금 public 에 대한 개념이 잡혔습니다!

ikpil의 이미지

private 보단
실무에선 클래스 내부의 객체의 보유로 A has B 로 해결하요?
포인터나 레퍼런스로 보유할것 같은 느낌이 팍팍 듭니다!

klara의 이미지

전 프로그래머가 아니기 때문에 실무에 대해선 잘 모르지만, 답은 '경우에 따라다르다'일 것입니다.
사실 private 상속은 '... has a ...'외에, '... is implemented in terms of ...'의 관계도 있습니다.
자세한 내용을 하자면 길어지므로, 직접 제가 참고하고 있는 Effective C++을 읽어보시길 추천합니다(사실 저도 완전히 알진 못해서 더 자세히 설명하기 힘들기도 합니다-_-;).

neogeo의 이미지

모든게 항상 이론대로 되면 좋겠지만....

일단 상속의 주된 이유는 code re-use 를 위한 것 입니다. ( 전 이렇게 생각합니다. )

계층 구조를 깔끔하게 이루면 한번 코딩해서 수많은 객체의 성질을 어느정도 공통된 부분에 정의를 쉽게 내릴 수 있게 되지요...

has-a, is-a, is-implemented-in-terms-of 등은 이론적으로 그렇게 하는게 좋다는 것이고 실질적으로는 되도록 코딩양을 줄이면서 이 코드를 보는 사람이나 이 코드에서 파생된 결과물을 쓰는 사람에게 이롭게 하는게 가장 좋다는 것을 항상 고민하면서 코딩하시면 어느정도 답이 보이실 것입니다.

상속의 단계나 다중 상속의 갯수에 대해 무조건 제한을 둔다! 라는것은 없습니다.

다만 이정도 상속이 이어진다던가 이정도 복잡하게 서로 상속이 꼬이면 이해가 가지 않으므로 피하는게 좋다.. 정도가 정석입니다.

누가 봐도 명확한 것은 되도록 상속을 하고 아닌것은 단지 레퍼런스나 포인터 , 객체를 직접 지니게 하는것도 아주 좋은 방법입니다. ( has-a 의 경우 상속보다 직접 객체를 내부에 포함 하는 케이스가 많죠. )

상속을 많이 할수록 code re-use 의 경향은 커지지만 복잡도는 증가하는게 일반적입니다.

게임쪽의 책들은 대부분 3단계 이상의 상속을 꺼립니다. ( 기본 라이브러리는 물론 예외입니다. 특정한 게임엔진의 경우는 5,6 단계 이상의 상속도 자주 사용하곤 했습니다. ) 정말 자주 요구사항이 변하고 객체에 대한 내용이 자주 바뀌는 경우는 각 객체간의 의존도를 최대한 줄여야 오히려 코딩양이 줄기 때문입니다. ( 변화할 때마다 모조리 고쳐야 한다고 가정해 보십시오. 객체 간의 의존도가 적으면 , 즉 상속 관계가 적으면 오히려 변화를 줄때 코딩양이 줄 수 있습니다. )

다중 상속은 대부분 피하는것이 상책이라고 되어있습니다.

이는 dynamic_cast 를 자주 활용해야 하는 곳에서 문제를 일으킬 소지가 매우 다분하기 때문입니다.

저역시 다중상속은 일단 꺼리지만, 다중상속을 사용해서 코드내용이 더 좋아지고 사용하기 편해진다면 씁니다.

대부분 객체의 성격이나 이런것을 정의하기 위해 상속만을 고집하는 경우가 많은데, 사실 moden c++ design 이란 책을 꼭 보길 권합니다.

template 을 이용하여 policy template class 등을 활용하면 코딩양을 줄이면서 상속을 사용하지 않고도 각종 객체의 여러가지 성향을 직접 조절할수 있는 예제가 매우 많이 나옵니다. ( 메모리 관리자는 A 를 사용하면서 스마트 포인터의 관리를 받지않고 반드시 singleton 이어야 한다.. 등등 여러가지 각 객체의 기본성질을 결정해야 할 일이 매우 많죠 )

일단 xylosper 님 말씀대로 effective c++ 을 읽으신뒤 modern c++ design 책을 꼭 여러번 읽어보시길 강력 추천합니다.

Neogeo - Future is Now.

Neogeo - Future is Now.

glay의 이미지

네억 +_+

요즘 머 하고 살아욕?

하늘은 스스로 삽질 하는 자를 삽으로 팬다.
------------------------------------------------
http://glay.pe.kr


--------------- 절취선 ------------------------
하늘은 스스로 삽질하는 자를 삽으로 팬다.

http://glay.pe.kr

semmal의 이미지

C++는 부모 클래스의 내용이 자식 클래스에 "embed"되기 때문이죠.

Java는 부모 클래스에 자식 클래스가 "link" 됩니다.

그래서 C++는 OO를 쓸 수 있으면서도 안쓰는 것이 좋은 때가 꽤나 있습니다.
------------------------------
How many legs does a dog have?

------------------------------
How many legs does a dog have?

정태영의 이미지

'link' 와 'embed' 는 말과 구현 상의 사소한 차이일 뿐 실제로는 거기서 거기일 것 같습니다.

그리고 상속은 편의를 위한 것이지 성능을 위한 게 아니라고 생각합니다. 상황을 봤을 때 상속을 여러번 하게 되더라도 새로 구현을 해야할 부분을 적게만들 수 있다면 여러번 상속하는게 맞지 않을까요 ;)

--
오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

semmal의 이미지

절대 상속을 많이 하면 안된다는 건 아니지요.

편의를 위한 것이지 성능을 위한 게 아니라는 말도 옳으신 말씀입니다.

하지만 C++를 써서 OO를 쓰는 사람이라면 이런 문제 정도는 알고 있어야 한다고 생각이 들었거든요.

우리 주위에도 나중에 성능 안나온다고 C++를 욕하는 사람이 꽤나 있지 않습니까?
------------------------------
How many legs does a dog have?

------------------------------
How many legs does a dog have?

klara의 이미지

Java와 C++에서 차이가 있단건 처음 알았네요.
그런데, C++에서 상속이 부모클래스를 포함시켜버린다면, 코드는 늘어날지 몰라도, 오히려 성능면에선 더 좋은 것 아닌가요...?

semmal의 이미지

소스가 충분히 작을 때만 그렇습니다.

메모리를 많이 점유하면 속도도 떨어지게 됩니다.

뿐만아니라 잦은 재컴파일로 인해서 개발속도도 저하되죠.
------------------------------
How many legs does a dog have?

------------------------------
How many legs does a dog have?

정태영의 이미지

링크가 된다고 하더라도 (reference 만 가진단 얘기가 맞겠죠?) 링크의 주체가 되는 객체가 할당되야 할테니 똑같은 메모리 공간이 필요할 것이라 생각됩니다.

한 객체를 공유할 수 있는 상황이라면야 c++ 에서도 포인터를 사용해서 구현하면 되니 문제될 것이 없어보이구요.

--
오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

semmal의 이미지

지금 설명하신 것이 링크고 임베드가 되면 자식 클래스의 갯수만큼 부모 클래스가 복사가 됩니다.
------------------------------
How many legs does a dog have?

------------------------------
How many legs does a dog have?

klara의 이미지

그럼 Java에서는 모든 자식 클래스의 인스턴스가 같은 부모 클래스의 인스턴스를 공유한다는 말씀인가요..?
예를 들어 A라는 클래스가 멤버 int m을 가지고 있고, A를 상속 받은 클래스 B를 정의한다음, B의 객체로 b1, b2를 만들면, b1.m을 수정하면 b2.m도 바뀔 텐데...이건 말이 안되고...뭔가 제가 잘못 생각하고 있는걸까요?

정태영의 이미지

말씀하신 링크라는 것에 대한 얘기였습니다.

자식 클래스들에서 공통으로 사용하게 되는 static 변수가 아닌 이상에야 자바든 c++ 이든 embed 되었든 link 되었든 똑같은 공간이 필요하게 될 수 밖에 없습니다.

--
오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

heonjushin의 이미지

저 같은 경우 상속의 깊이는 제한을 두지 않습니다. 3,4단계 이상 깊어지면 코드 분석하거나 리딩할 때 좀 버겁지만 필요하다면 상속을 해야죠. 그리고 요즘 많은 책들에서 강조하듯 상속을 사용할 때 한번 더 생각해봐야합니다. 윗 분들도 언급했듯이 is-a 일 때만 public 상속을 사용하고 has-a는 상속을 사용하지 않고 포함을 사용합니다. is-implemented-in-terms-of도 기본적으로 has-a 관계로 보는게 좋습니다. 이 경우도 non-public 상속을 굳이 사용하지 말고 포함을 사용하는 게 좋습니다. base클래스의 멤버함수 override해야하는 경우 같이 특이case가 아니라면 상속을 쓰지 않습니다.
다중 상속은 정말 어려운 문제인 것 같습니다. 쓸 경우도 많지 않고 제대로 쓰는 법도 잘 모르겠습니다. name confliction, 다이아몬드 상속, ... 고려해야 할 것이 많으므로 가급적 쓰지 않는 것이 좋겠습니다만 정말 필요하다면 써야겠죠^^;

semmal의 이미지

서브타이핑과 서브클래싱만 구별해서 쓰면 문제가 전혀 발생하지 않습니다.

꼭 서브클래싱을 써야할 때는 델리게이션으로도 충분히 해결가능합니다.

물론 귀찮음은 감수해야죠. 그 귀찮음이 나중에 소스보면서 하염없이 고민 하는 시간보다는 훨씬 나을겁니다.
------------------------------
How many legs does a dog have?

------------------------------
How many legs does a dog have?

codepage의 이미지

위 Post들를 읽어보니 C++에서 3-4단계 상속을 할 경우 속도가 느려진다고 하셨는데.
사실 저는 속도가 그리 문제가 되지 않는 환경(1GHz 이상의 CPU, 요즘 나오는 PC)에서 작업을 하기 때문에 그렇게
몸으로 느낄만큼의 문제점은 못 느껴봤습니다.

우리가 사용하고 있는컴퓨터는 아무리 날고 긴다고 해봤자 노이만 아저씨가 만든 프로그램 내장형 방식의 기반 위에서 만들어진 것이고
그래서 그 연산속도는 CPU의 연산속도와 메모리에 왔다갔다 하는 데이타의 량에 의해서 좌우됩니다. (SWAP이 일어나지 않는다고 가정)

만약 File I/O와 같이 특별히 다른 일을 하지 않는 이상 3-4단계 다중 상속을 한다고 문제가 될까요?
만약 10MHZ짜리 CPU 정도를 사용한다면 또 그럴수도 있죠. 만약 그런 환경 하에서 우리가 말하는 소위 '미션 크리티컬'한
어플리캐이션을 짠다면, 뭐 다른 언어를 사용해 보심이 바람직할 수도 있겠고요.

또한 그런 환경에서 굳이 C++을 사용해서 답을 구하고 싶으시다면 우리가 흔히 말하는 stub/skelecton방식을 응용해 보심이..
즉, 부모 클래스들은 일종의 프로토타입과 기본적인 멤버 변수를 정의(맴버 변수가 있다는 것은 stub이란 의미와 정확히 어울리지는 않지만)
그리고 구체적인 구현은 가장 밑의 자식 클래스에서 하면 좀 낫지 않을까요?
또 클래스의 생성과 소멸을 언제 어떻게 하느냐도 속도 문제와 관련이 있을수도 있겠구요. 또 한가지 추측되는 문제는 실제로 사용할 수 있는 Physical memory보다 많은 양의 memory를 사용할 경우 O/S가 swap space를 사용할 수도 있는데 이렇게 되면 진짜 현저한 속도 차이가 납니다.

참고로 제 경험을 말씀드리면 제가 아키텍쳐를 설계할 때는 UML등을 사용해서 Class간의 relation을 정확하게 설계하는 것에 모든 신경을 집중하고요, 몇 단계 상속하느냐 이런 것은 신경도 쓰지 않습니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.