본문 바로가기

Windows Developer/C++

[C++] 가상함수

[출처]

NetGong 2009.09.04 17:01
http://blog.daum.net/coolprogramming/69

먼저 간단히 부모와 자식간의 함수 호출을 설명하도록 하겠습니다.

#include<iostream>
using namespace std;
class Person
{
 char name[20];
             int age;
public:
             Person(const char* n, int a)
            {
                    strcpy(name, n);
                    age = a;
            }
            void Eat(){ cout<<"eat!!"<<endl;}
            void Print() const
           {
                    cout<<"name : "<<name<<", "<<"age : "<<age<<endl;
           }
           const char * GetName() const { return name; }
           int GetAge() const { return age; }
};

class Student : public Person
{
           int grade;
public :
           Student(const char * n, int a, int g) : Person(n, a), grade(g){}
           void Study() { cout<<"study!!"<<endl;}
           void Print() const
          {
                   cout<< "name : "<<GetName()<< ", "<<"age : "<<GetAge()<<", ";
                   cout<< "grade : "<<grade<<endl;
          }
           int GetGrade() const {return grade;}
};

void main()
{
           Person person1("홍길동", 27);
           Student student1("김학생", 20, 1);
           person1.Print();
           student1.Print();
}


출력결과는 간단합니다.

다음은 포인터를 사용한 예를 들도록 하겠습니다.
Person class 와 Student class는 동일하고 메인문만 바꿔보도록 하겠습니다.

void main()
{
            Person person1("홍길동", 27);
            Student student1("김학생", 20, 1);
            //person1.Print();
            //student1.Print();
            Person *pPerson = &person1;
            Student *pStudent = &student1;
            pPerson->Print();
            pStudent->Print();
}

pPerson이 Person 객체의 주소이므로 멤버 함수 Print()를 -> 연산자로 호출합니다.
pStuendt도 동일하며, 출력 결과는 위와 같습니다.



1. 가상함수

 - 부모 클래스의 포인터는 자식 객체의 주소를 가리킬 수 있습니다.
    Person 클래스의 포인터는 Student 객체의 주소를 가리킬 수 있습니다.
 - 부모 클래스의 레퍼런스는 자식 객체를 가리킬 수 있습니다.
    Person 클래스의 레퍼런스는 Student 객체를 가리킬 수 있습니다.

개념적으로 Student도 Person이기 때문입니다.

아래 예제는 부모 포인터로 자식 객체를 가리키는 예제 입니다.

void main()
{
Person *pPerson;//Person 포인터를 선언

Person person1("홍길동", 27);
pPerson = &person1;

Student student1("김학생", 20, 1);
pPerson = &student1;//중요한 문법, 학생도 사람이기 때문에 가능
}

결과가 아주 중요합니다. pPerson 포인터가 가리키는 객체가 Student 임에도 불구하고 Person의 Print()함수가 호출됩니다.

이것은 당연히 잘못된 결과입니다.
이것은 학생에게 "너의 학생 정보를 출력하렴"이라고 질문하니 "전 단지 사람일 뿐입니다" 이렇게 말하는 것과 같습니다.
학생에게 " 네 정보를 출력해 보렴?" 이라고 질문하면 " 전 학생이며, 이름, 학년이 이렇게 됩니다"라고 말해야 합니다.
이 문제를 해결하기 위해 등장하는 놈이 바로 가상함수(virtual function)입니다.
부모 클래스에서 정의한 함수를 자식 클래스에서 재정의 했다면 위와 같은 문제를 해결하기 위해 꼭 재정의 함수를 가상함수로 만들어야 합니다.


방법은 간단합니다. 'virtual' 키워드만 재정의 함수에 붙여주면 됩니다.


#include<iostream>
using namespace std;
class Person
{
 char name[20];
             int age;
public:
             Person(const char* n, int a)
            {
                    strcpy(name, n);
                    age = a;
            }
            void Eat(){ cout<<"eat!!"<<endl;}
            virtual void Print() const
           {
                    cout<<"name : "<<name<<", "<<"age : "<<age<<endl;
           }
           const char * GetName() const { return name; }
           int GetAge() const { return age; }
};

class Student : public Person
{
           int grade;
public :
           Student(const char * n, int a, int g) : Person(n, a), grade(g){}
           void Study() { cout<<"study!!"<<endl;}
           void Print() const
          {
                   cout<< "name : "<<GetName()<< ", "<<"age : "<<GetAge()<<", ";
                   cout<< "grade : "<<grade<<endl;
          }
           int GetGrade() const {return grade;}
};

void main()
{
           Student student1("김학생", 20, 1);
           Person *pPerson = &student1;
 
           pPerson->Print();//이제 정확히 Student의 Print() 함수를 호출합니다
}

이제 정확한 결과가 출력됩니다. 학생에게 "너의 정보를 출력해 보렴?" 이라고 질문하면 "전 학생이며 이름, 나이, 학년은 이렇습니다"라고 대답합니다

이제 정리하는 의미에서 Professor 클래스를 추가한 예제를 보겠습니다.
예제 클래스의 구조



 #include <iostream>
using namespace std;
class Person
{
    char name[20];
    int age;
public:
    Person(const char* n, int a)   
    {
        strcpy(name, n);
        age = a;
    }
    void Eat( ) {   cout << "eat!!!" << endl; }
    virtual void Print( ) const
    {
        cout << "name : " << name <<", " <<"age : " << age << endl;
    }
    const char* GetName( ) const { return name; }
    int GetAge( ) const { return age; }
};
class Student : public Person
{
    int grade;
public:
    Student(const char* n, int a, int g):Person(n,a), grade(g) {    }
    void Study( ) { cout << "study!!!" << endl; }
    void Print( ) const
    {
        cout << "name : " << GetName( ) <<", " <<"age : " << GetAge() <<", ";
        cout << "grade : " << grade << endl;
    }
    int GetGrade( ) const { return grade; }
};
class Professor : public Person
{
    char position[20];
public:
    Professor(const char* n, int a, const char* p):Person(n,a)
    {
        strcpy(position, p);
    }
    void Teach( ) { cout << "teach!!!" << endl; }
    void Print( ) const
    {
        cout << "name : " << GetName( ) <<", " <<"age : " << GetAge() <<", ";
        cout << "position : " << position << endl;
    }
    const char* GetPosition( ) const { return position; }
};
void main( )
{
    Person *pPerson;
    Person person1("홍길동", 27);
    Student student1("김학생", 20, 1);
    Professor professor1("김교수", 45, "부교수");

    pPerson = &person1;
    pPerson->Print(); //사람의 정보가 출력됩니다.

    pPerson = &student1;
    pPerson->Print(); //학생의 정보가 출력됩니다.

    pPerson = &professor1;
    pPerson->Print(); //교수의 정보가 출력됩니다.
}



'Windows Developer > C++' 카테고리의 다른 글

[C++] 초기화 리스트(Initialize List)  (1) 2010.07.26
[C++] 형변환 연산자  (0) 2010.07.26
[C++]템플릿(template)  (0) 2010.07.20
[C++]STL 표준 C++ 라이브러리  (0) 2010.07.20
[C++]상수 함수  (1) 2010.07.19