c++ 상속, 가상함수

j03y14의 이미지

class CWall {
 
public:
 
 virtual bool hasIntersected() {
  cout << "CWall hasIntersected" << endl;
  return false;
 }
};
 
class VirticalCWall :public CWall {
public:
 int c=1;
 virtual bool hasIntersected() {
  cout << "VirticalCWall hasIntersected" << endl;
  return false;
 }
};
 
class HorizonalCWall :public CWall {
public:
 int d = 1;
 virtual bool hasIntersected() {
  cout << "HorizonalCWall hasIntersected" << endl;
  return false;
 }
};
int main()
{
 <span> CWall g_legowall[2];
 g_legowall[0] = VirticalCWall();
 g_legowall[1] = HorizonalCWall() ;</span>
 
 
 <span>/*CWall* g_legowall[2];
 g_legowall[0] = new VirticalCWall();
 g_legowall[1] = new HorizonalCWall();
 */</span>
 
 for (int i = 0;i<2 ;i++) {
 <span> g_legowall[i].hasIntersected();</span>
   <span>//g_legowall[i]->hasIntersected();</span>
 }
 
 return 0;
}

왜 주석처리한 방법으로 객체를 생성해야만 상속받은 객체의 가상함수가 출력되고,
주석처리하지 않은 방법으로 겍체를 생성하면 부모 객체의 가상함수가 출력이 될까요?

주석처리하지 않은 방법으로 객체를 만들고 이용해서 자식 객체의 가상함수를 출력하는 방법이 없나요?

 의 이미지

자바 같은 언어 쓰다가 오셨나요??

C++에서 base class의 포인터나 참조자를 정의했다면 그것은 derived class의 객체를 가리킬 수 있습니다.
그러나 애초에 base class의 객체를 직접 정의했다면 그것은 곧 죽어도 base class의 객체입니다.

다시 말해, 다형성(Polymorphism) 기능을 제대로 쓰고 싶다면 주석처리된 코드처럼 포인터를 사용하거나, 아니면 참조자를 쓰셔야 된다는 얘기입니다.

주석처리 안 된 코드가 무사히 컴파일되는 것을 보고 착각하실 수 있는데, 저 코드는 질문자님이 의도하신 대로 절대 동작하지 않습니다.

C++는 g_legowall[0] = VirticalCWall();를 이렇게 해석합니다.
1. VirticalCWall 타입의 temporary를 생성하고
2. 그 temporary를 CWall타입의 객체 g_legowall[0]에 복사 배정합니다.
2-1. 말인즉슨 g_legowall[0]에 대해 복사 배정 연산자 CWall &CWall::operator=(const CWall &)이 호출된다는 겁니다. 이 연산자를 정의한 적이 없다고 하셔도 마찬가집니다. 컴파일러가 자동으로 만들어줍니다.
2-2. 여기서 복사 원본이 되는 것은 앞서 언급한 temporary인데, 이는 사실 VirticalCWall 타입이지만 상속 관계에 의해 OWall이기도 하므로 자동으로 업캐스팅이 수행되어 문제 없이 복사 배정이 일어납니다.

결국 갓 만들어진 VirticalCWall 타입 temporary의 OWall 부분만이 g_legowall[0]에 복사된다는 얘깁니다.

대입 이후에도 g_legowall[0]는 여전히 OWall 객체이므로, 가상 함수를 호출해도 당연히 OWall의 것이 호출됩니다.

감히 말씀드리건대, 이런 식으로 암시적으로 업캐스팅이 일어나서 객체의 일부만이 복사되는 상황은 일단 경계대상입니다. 무슨 일이 일어나는지 정확히 이해한 상황에서 일부러 그런 게 아니라면 말이죠. 말인즉슨, 실수로 이런 짓을 하기가 C++에서는 너무 쉽다는 얘깁니다.

DISCLAIMER: C++11 혹은 그 이후의 C++를 사용중이라면 복사 배정이 아니라 이동 배정이 됩니다. 어쨌든 논지는 안 달라져요.

댓글 달기

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