상속
여러 클래스가 어떤 특정 공통점을 가지고 있을 때 공통점 만을 모아서 따로 클래스를 만들고 나머지 는 그 클래스의 내용을 물려(상속)받아 쓰는 개념
상속 정의
class Parent
{
public:
Parent()
{}
~Parent()
{}
}
class Child
{
public:
Child()
{}
~Child()
{}
}
다음과 같은 두 클래스가 있을 때
class Parent
{
public:
Parent()
{}
~Parent()
{}
}
class Child
: public Parent
{
public:
Child()
{}
~Child()
{}
}
다음과 같이 Child 클래스에 : public Parent 를 추가 하면
Child 클래스는 Parent 클래스를 상속받게 되고 Parent 클래스는 child 클래스에 대한 부모 클래스, Child 클래스는 Parent 에 대한 자식클래스라 한다.
상속에서 제한 지정자
class Parent
{
//private: // ...ㅁ
protected: // ...ㅂ
float m_fnum1;
int m_inum2;
public:
Parent()
{}
~Parent()
{}
}
class Child
: public Parent
{
public:
Child()
: m_fnum1(0.f); // ...ㄱ
, m_inum2(10); // ...ㄴ
{
m_fnum1 = 0.f; // ... ㄷ
m_inum2 = 10; // ... ㄹ
}
~Child()
{}
}
ㄱ,ㄴ 은 불가능하고 ㄷ, ㄹ 은 가능하다.
이는 자식 클래스 생성자 에서 부모 맴버를 초기화 할 수 없다.
맴버 초기화는 자신이 속한 맴버만 대상으로 한다.
이때 부모 클래스의 맴버함수가 private 일때 ㄷ, ㄹ 도 불가능하지만 protected 일때에는 ㄷ, ㄹ 이 가능하다.
상속에서 생성자와 소멸자
class Parent
{
protected:
float m_fnum1;
int m_inum2;
int m_inum3;
public:
Parent()
{}
Parent(float _f1, int _i2, int _i3) // ... ㄷ
: m_fnum1(_f1)
, m_inum2(_i2)
, m_inum3(_i3)
{}
~Parent()
{}
}
class Child
: public Parent
{
private:
int m_iChild;
public:
Child()
: Parent() // ... ㄱ
, m_iChild(0) // ... ㄴ
{
m_fnum1 = 0.f;
m_inum2 = 10;
}
Child(float _f1, int _i2, int _i3, int _i4) // ... ㄹ
: Parent(_f1, _f2, _f3)
, m_iChild(_i4)
{}
~Child()
{}
}
int main()
{
Child c1;
Child c2(10.f, 20, 30, 40) // ...ㅁ
return 0;
}
위와 같은 코드에서 ㄱ 은 원래 생략되어 있다. 이를 통해 생성자의 호출 순서를 알 수 있다.
객체 c1 선언할 때 생성자 호출과 초기화 순서는 다음과 같다
1. Child 생성자 호출
2. Parent 생성자 호출
3. Parent 맴버 초기화
4. Child 맴버 초기화
이와 반대로 소멸자의 경우
1. 자식의 소멸자를 실행한다
2. 부모의 소멸자를 실행한다
ㄱ과 ㄴ 은 순서를 바꿀 수 있지만 그렇다고 초기화인 ㄴ 이 먼저 실행되는 것이 아니라 순서 상관없이 ㄱ 이 먼저 실행된다.
ㄷ, ㄹ, ㅁ, 과 같이 사용도 가능하다.
오버라이딩
class Parent
{
protected:
float m_fnum1;
int m_inum2;
int m_inum3;
public:
void Output() //...ㄱ
{
cout<< "Parent" << endl;
}
Parent()
{}
~Parent()
{}
}
class Child
: public Parent
{
private:
int m_iChild;
public:
void Output() //...ㄴ
{
cout<< "Child" << endl;
}
Child()
: Parent()
, m_iChild(0)
{
m_fnum1 = 0.f;
m_inum2 = 10;
}
~Child()
{}
}
int main()
{
Parent p1;
p1.Output(); // ... ㄷ
Child c1;
c1.Output(); // ... ㄹ
c1.Parent::Output(); //...ㅁ
return 0;
}
ㄷ과 ㄹ을 실행할 때 ㄷ은 ㄱ을 ㄹ은 ㄴ을 호출한다.
오버라이딩이란
상속관계에서만 발생하는 개념으로 부모클래스의 맴버 함수를 자식 쪽에서 재정의 함으로써, 자식 클래스에 구현된 기능이 호출되도록 하는 것이다.
ㅁ은 Child 클래스를 자료형으로 하는 객체가 이미 부모 클래스인 Parent 의 Output 함수를 오버로딩 (덮어쓰기) 했지만 부모 클래스에 정의 되어 있는 Output 함수 (오버라이딩 되기 전)를 호출하는 경우이다.
* 오버로딩이란
함수명이 은 같지만 인자가 차이가 있는 함수가 2개 이상 존재하는 것을 뜻한다.
오버로딩은 함수명이 같고 인자가 달라야 하지만 오버 라이딩은 함수명과 인자 둘다 같은 것을 말한다.