본문 바로가기

Archived(CSE Programming)/cpp

Chap 8. 상속과 다형성

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


추가로 참조자도 객체 포인터와 마찬가지로 같은 구조를 지니고 같은 결과를 가져온다.