void Person::ShowPersonInfo()
{
cout << name_ << "의 나이는 " << age_ << "살입니다." << endl;
}
...
void Student::ShowPersonInfo()
{
cout << "이 학생의 학번은 " << student_id_ << "입니다." << endl;
}
==> 실행 결과
순신의 나이는 35살입니다.
이 학생의 학번은 123456789입니다.
1)Person 클래스의 ShowPersonInfo() 멤버 함수를 Student 클래스에서 상속받아 재정의
2) Student 객체에서 ShowPersoninfo() 멤버 함수를 호출
3) 기초 클래스인 Person 클래스의 멤버 함수가 아닌 재정의한 멤버 함수가 호출됨을 알 수 있다.
Student hong(123456789, "길동", 29);
hong.ShowPersonInfo();
hong.Person::ShowPersonInfo();
==>실행 결과
이 학생의 학번은 123456789입니다.
길동의 나이는 29살입니다.
Person* ptr_person;
Person lee("순신", 35);
Student hong(123456789, "길동", 29);
ptr_person = &lee;
ptr_person->ShowPersonInfo();
ptr_person = &hong;
ptr_person->ShowPersonInfo();
==>실행 결과
순신의 나이는 35살입니다.
길동의 나이는 29살입니다.
1) Person 객체를 가리킬 수 있는 포인터 변수 ptr_person을 생성하여, Person 객체의 주소값을 대입
2) 포인터 변수에 멤버 접근 연산자(->)를 사용해 Person 객체의 ShowPersonInfo()함수를 호출.
3) Student 객체의 주소값을 대입하고, 이번에는 Student객체의 ShowPersonInfo()함수를 호출.
4) 두 번 모두 Person 객체의 ShowPersonInfo() 함수가 호출된다.
왜냐하면, C++ 컴파일러는 포인터 변수가 실제로 가리키는 객체의 타입을 기준으로 함수를 호출하는 것이 아니라, 해당 포인터의 타입을 기준으로 함수를 호출하기 때문. 따라서 Person 객체를 가리킬 수 잇는 포인터 변수로는 Person 객체의 멤버 함수만을 호출할 수 있다.
==> 이러한 문제점을 해결하기 위해서 virtual 키워드를 사용한 가상 함수를 제공하고 있다.
class Student : public Person
{
private:
int student_id_;
public:
Student(int sid, const string& name, int age); // 파생 클래스 생성자의 선언
virtual void ShowPersonInfo(); // 파생 클래스에서 상속받은 멤버 함수의 재정의
};
==>실행 결과
순신의 나이는 35살입니다.
이 학생의 학번은 123456789입니다.