2011. 5. 24. 22:50ㆍC++
[C++] 상속
1. 상속의 기본
상속을 하게 되면 아래와같이 수행된다.
- 메모리 공간 할당( Base 클래스와 Derived 클래스에 대한것 모두)
- Base 클래스의 생성자 실행
- Derived 클래스의 생성자 실행
ex> class Student : public Person
- 생성자 호출 순서
Base > Derived
* 하위 생성자안에 상위 생성자가 명시되어 있지 않으면 디폴트 생성자(Void)가 호출됩니다.
- 상위의 생성자를 지정하는 방법
class Person {
Person(int value){}
}
class Student: public Person{
Student(char*name, int value): Person(value) // 이와같이 부모클래스의 생성자를 지정 가능
{
}
}
- 소멸자의 호출 순서
* 자식 클래스의 소멸자부터 호출됩니다.
자식 클래스의 소멸자 > 부모 클래스의 소멸자 > 메모리 반환
- 상속에 관련된 접근 제한
protected 로 선언된 변수 및 함수는 상속관계에 있는 클래스에서 접근이 가능합니다.
(단, 외부에서는 접근이 불가합니다.)
2. 세가지 형태의 상속
- Base 클래스의 멤버는 상속되는 과정에서 접근 권한이 변경 됩니다.
class Student: public Person // 대부분의 상속, 부모클래스의 protected와 public만 접근 가능
class Student: protected Person // 부모클래스의 public 변수/함수들이 모두 protected로 변환
class Student: private Person // 부모클래스의 public 변수/함수들이 모두 private 로 변환
단) 부모클래스의 private 변수 자식 클래스에는 어떤 경우라도 접근 불가하다.
3. 객체 포인터
- 객체의 주소값을 저장할 수 있는 포인터
- Base 클래스의 포인터는 Base 객체 뿐만 아니라 Derived 클래스 객체의 주소값도 저장 가능하다.
- Base 클래스의 포인터의 접근은 Base 클래스의 멤버를 먼저 가리킨다.
즉 Base* b = new Derived 라 했을때, Derived에 log() 함수가 있을지라도 b.log() 했을때
Base의 log() 함수가 실행된다.
Person => Student => FirstGradeStudent 의 상속관계 일때
class Student : public Person
class FirstGradeStudent : public Student
Person* p = new Student; //가능
Person* p = new FirstGradeStudent; // 가능
Student* s = new FirstGradeStudent; // 가능
4. 객체 레퍼런스
- 객체를 참조할 수 있는 레퍼런스
- 클래스 포인터의 특성과 일
- 객체를 참조하는 레퍼런스의 권한은 클래스 포인터의 권한과 일치 합니다.
FirstGradeStudent& fgs;
Person& p = fgs;
Student& s = fgs;
5. 오버라이딩
- Base 클래스에 선언된 멤버와 같은 형태의 멤버를 Derived 클래스에서 선언
class Person {
virtual log(char* msg){}
}
class Student: public Person{
log(char* msg){}
}
Person* p = new Student;
p->log(); // Student의 log 함수가 호출된다. (virtual 가상함수로 선언되었기 때문에)
* 하위 클래스의 가상함수내에서 상위의 가상함수 호출 방법
Person::log();
- 멤버 함수를 가상(virtual)으로 선언하기
* virtual 특성도 상속된다. (자식클래스에 해당 함수도 자동으로 virtual이 된다.)
6. 순수 가상함수와 추상 클래스
- 추상 클래스: 순수 가상함수를 1개 이상 가지고 있는 클래스를 말한다.
# 객체화 불가함.
- 순수 가상함수: 선언만 하고 정의 안하는 방법
virtual int log()=0; // 이와 같이 하면 선언만 하게 된다.
7. 상속관계에서의 소멸자 문제점과 해결
* delete 할때의 문제점
class Person {
virtual log(char* msg){}
}
class Student: public Person{
log(char* msg){}
}
int main() {
Person* p = new Student;
delete p; // Person 클래스내의 소멸자만 호출되어 메모리 릭이 발생한다.
}
=> 이문제를 해결하기 위해서는 Base 클래스의 소멸자에 virtual를 선언하면 된다.
그러면 해당 소멸자는 자동으로 하위/상위 클래스를 해제하게 된다.
virtual ~Person(){}