프로그래밍 언어/cpp

[C++] 클래스 상속

TyT. 2023. 2. 12. 22:45
반응형

상속

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

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

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

반응형