Chap 8. 상속과 다형성
8-1. 객체 포인터의 참조관계
객체 포인터 변수는 해당 자료형의 객체 뿐만 아니라 해당 객체를 직간접적으로 상속하는 모든 객체를 가르킬 수 있다.
그렇지만 특정 포인터의 자료형에 따라 사용할 수 있는, 접근할 수 있는 범위는 제한된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include <iostream> class Person{ // 멤버변수 private: int age; // 멤버함수 public: Person(int a) : age(a){} void funct(){ std::cout<<"person"<<std:endl; } }; class Student :public Person{ // 멤버 변수 private: int grade; // 멤버 함수 public: Student(int a, int g) :Person(a), grade(g){} void funct(){ std::cout<<"Student"<<std:endl; } }; void main(){ Person * pptr = new Person(20); Person * pptr2 = new Student(20,1); pptr->funct(); // person 출력 pptr2->funct(); // person 출력 } | cs |
그리고 하위 클래스에서 상위 클래스의 함수를 재정의하여 가려버리는 것을 오버라이딩이라고 표현한다.
Person에서 정의 되어있는 funct 함수를 Student 에서 재정의하여 다른 결과를 가져오도록 하는 함수를 정의하였다.
8-2. 가상함수(Virtual Function)
이렇게 특정 객체를 상위 클래스 포인터 자료형으로 가르킬 수 있는데 위에서도 같은 출력 결과를 가져온다.
이렇게 되면 우리가 구현하고자 하는 다형성(같은 형태로 다른 결과를 가져오는 특성)을 구현할 수 없다.
따라서 우리는 키워드 virtual 을 통해 가상함수로 지정해주게 되면 해당 포인터가 가르키고 있는 실제 객체의
class에 오버라이딩 되어있는 최종 함수 형태를 호출하게 된다.
즉, 동적 바인딩이 일어나서 포인터 자료형에 따라 접근할 수 있는 범위가 제한되었던 것이 가상함수에서는 해제되어
경계가 동적으로 작동하는 것이다.
(Java와 달리 virtual 이라는 키워드를 통해 오버라이딩 하고자 하는 상위 클래스 함수에 적어줘야만 오버라이딩이 이루어진다)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <iostream> class Person{ // 멤버변수 private: int age; // 멤버함수 public: Person(int a) : age(a){} // 가상함수 선언 virtual void funct(){ std::cout<<"person"<<std:endl; } }; class Student :public Person{ // 멤버 변수 private: int grade; // 멤버 함수 public: Student(int a, int g) :Person(a), grade(g){} // 가상함수 선언 virtual void funct(){ std::cout<<"Student"<<std:endl; } }; void main(){ Person * pptr = new Person(20); Person * pptr2 = new Student(20,1); pptr->funct(); // person 출력 pptr2->funct(); // student 출력 } | cs |
8-3. 가상 소멸자와 참조자의 참조 가능성
소멸자도 마찬가지로 가상함수로 선언해줘야 실제 가르키고 있는 객체를 전부 delete 해줄 수 있다.
특히, 동적 할당한 멤버 변수가 있을 경우 더욱이 신경 써주어야 한다.
따라서 다음과 같이 지정해주어야 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include <iostream> class Person{ // 멤버변수 private: int age; // 멤버함수 public: Person(int a) : age(a){} // 가상함수 선언 virtual void funct(){ std::cout<<"person"<<std:endl; } // 가상 소멸자 virtual ~Person(){} }; class Student :public Person{ // 멤버 변수 private: int grade; // 멤버 함수 public: Student(int a, int g) :Person(a), grade(g){} // 가상함수 선언 virtual void funct(){ std::cout<<"Student"<<std:endl; } // 가상 소멸자 virtual ~Student(){} }; void main(){ Person * pptr = new Person(20); Person * pptr2 = new Student(20,1); pptr->funct(); // person 출력 pptr2->funct(); // student 출력 delete pptr; delete pptr2; } | cs |
추가로 참조자도 객체 포인터와 마찬가지로 같은 구조를 지니고 같은 결과를 가져온다.
'Archived(CSE Programming) > cpp' 카테고리의 다른 글
Chap 10. 연산자의 오버로딩 1 (0) | 2019.01.12 |
---|---|
Chap 9. 가상(Virtual)의 원리와 다중상속 (0) | 2019.01.10 |
Chap 7. 상속(Inheritance)의 이해 (0) | 2019.01.08 |
Chap 6. friend와 static 그리고 const (0) | 2019.01.07 |
Chap 5. 복사 생성자(Copy Constructor) (0) | 2019.01.06 |