본문 바로가기
프로그래밍 언어/cpp

[C++] 클래스 상속

by TyT. 2023. 2. 12.
반응형

상속

앞선 포스팅에서도 언급한적이 있지만, 필자는 학부에서 자바를 배웠기 때문에 상속의 자세한 이론은 다루지 않을 것이다.

일단 상속을 전체적으로 다룬 예제코드다. 필자와 같이 상속에 대한 개념이 잡혀있다면 이 코드만봐도 대략적으로 이해가 될 것이다.

#include <iostream>

using namespace std;

class Parent
{
public:
    int a;
    float b;

public:
    void func()
    {
        cout << "부모멤버함수" << a << endl;
    }
    // virtual은 자식클래스를 Parent포인터로 받아서 vFunc함수를 호출하면 오버라이딩된 함수를 호출하게 해준다.
    virtual void vFunc()
    {
        cout << "부모버추얼멤버함수" << b << endl;
    }

public:
    Parent()
        : a(1), b(2)
    {
        cout << "부모생성자" << endl;
    }
    ~Parent()
    {
        cout << "부모소멸자" << endl;
    }
};

// 상속문법은 : public 부모클래스
class Child : public Parent
{
private:
    int a;

public:
    void func()
    {
        cout << "자식멤버함수(오버라이딩)" << a << endl;
    }
    virtual void vFunc()
    {
        cout << "자식버추얼멤버함수" << b << endl;
    }
    void cFunc()
    {
        // 부모 함수의 a를 사용하는 방법
        cout << "자식멤버함수" << Parent::a << endl;
    }

public:
    Child()
        : a(10)
    // , Parent()   // 생략된 부모 생성자. 명시하지않으면 기본 생성자를 호출.
    {
        cout << "자식생성자" << endl;
    }
    ~Child()
    {
        cout << "자식소멸자" << endl;
    }
};

int main()
{
    Parent parent;
    Child child;
    // 부모생성자
    // 부모생성자
    // 자식생성자

    cout << 1 << endl;
    parent.func();
    parent.vFunc();
    // 1
    // 부모멤버함수1
    // 부모버추얼멤버함수2

    cout << endl
         << 2 << endl;
    child.func();
    child.vFunc();
    child.cFunc();
    // 2
    // 자식멤버함수(오버라이딩)10
    // 자식버추얼멤버함수2
    // 자식멤버함수1

    cout << endl
         << 3 << endl;
    Parent *pPointer;
    // pPointer = &parent;   //당연히 문제없음
    pPointer = &child; // 가능.
    pPointer->func();
    pPointer->vFunc();
    // pPointer->cFunc();   //불가능. 포인터가 Parent타입이기 때문
    // 3
    // 부모멤버함수1
    // 자식버추얼멤버함수2

    cout << endl
         << 4 << endl;
    Child *cPointer;
    // cPointer = &parent;  //불가능
    cPointer = &child; // 당연히 가능
    cPointer->func();
    cPointer->vFunc();
    cPointer->cFunc();
    // 4
    // 자식멤버함수(오버라이딩)10
    // 자식버추얼멤버함수2
    // 자식멤버함수1

    cout << endl
         << 5 << endl;
    // cPointer = (Child *)pPointer;    //C스타일 강제캐스팅. 가능. 하지만 위험
    cPointer = dynamic_cast<Child *>(pPointer);
    if (nullptr != cPointer) // 다이나믹캐스트를 사용하면 오류검출이 가능해짐
    {
        cPointer->func();
        cPointer->vFunc();
        cPointer->cFunc();
    }
    // 5
    // 자식멤버함수(오버라이딩)10
    // 자식버추얼멤버함수2
    // 자식멤버함수1

    return 0;
    // 자식소멸자
    // 부모소멸자
    // 부모소멸자
}

상속 문법

class Child : public Parent

생성자

자식 클래스가 생성자를 호출시

자식 생성자 호출->부모 생성자 호출->부모 생성자 실행 -> 자식 생성자 실행

순으로 실행된다.

이때, 부모생성자를 명시하지않으면 기본생성자를 호출한다. 만약 오버로딩한 생성자를 호출하고 싶다면 명시할 것.

소멸자

자식 클래스 소멸자를 호출시

자식 소멸자 호출->자식 소멸자 실행 -> 부모 소멸자 호출 -> 부모 소멸자 실행

순으로 실행된다.

마찬가지로 부모소멸자를 필요시 명시할것.

포인터

부모클래스의 포인터는 자식클래스의 객체 주소값을 받을 수 있다. 하지만 포인터가 부모클래스이기 때문에 부모클래스의 멤버들만 사용이 가능하다.

반대로 자식클래스의 포인터는 부모클래스의 객체 주소값을 받을 수 없다.

virtual

virtual키워드는 부모클래스의 멤버함수에 선언시 부모클래스의 포인터가 자식클래스 객체를 받아서 멤버함수를 실행할때, 오버라이딩되어있다면 자식클래스의 멤버함수를 호출하게 해준다.

dynamic_cast

C스타일의 강제캐스팅의 역할을 안전하게 실행하게 해준다.(다운캐스팅) 사용방법은 예제 참조. 당연히 부모클래스 포인터가 자식클래스의 객체주소값을 받았을 때에만 자식클래스로 다운캐스팅이 가능하다.

반응형