반응형

 

업캐스팅 (UpCasting)

- C++에서, A 클래스 형 포인터 변수는 A 클래스의 객체 또는 A 클래스를 직, 간접적으로 상속하는 모든 객체를 가리킬 수 있다. (자식 클래스 객체의 주소값을 부모 클래스 포인터 변수에 담아 사용할 수 있다.)

- IS-A 상속 관계의 성립으로 인해서, 부모 클래스를 직, 간접적으로 상속하는 객체를 부모 클래스 객체의 일종으로 간주한다.

- 여러 자식 클래스들의 부모 클래스가 동일 할 경우 해당 부모 클래스에 여러 자식 클래스를 일괄적으로 처리가 가능하다.

#include <iostream>
using namespace std;

class Parent
{
public:
    void ShowParent()
    {
        cout << "Parent class" << endl;
    }
};

class Son : public Parent
{
public:
    void ShowSon()
    {
        cout << "Son class" << endl;
    }
};

class Daughter : public Parent
{
public:
    void ShowDaughter()
    {
        cout << "Daughter class" << endl;
    }
};

void main()
{
    Parent* ptr[2] = { new Son(), new Daughter() };
    for (int i = 0; i < 2; i++)
    {
        ptr[i]->ShowParent();
    }
    
    //결과
    //Parent class
    //Parent class
}

 

 

※ 업캐스팅 사용시 주의사항

- 위와 같이 업캐스팅하여 함수를 호출할 때 다음과 같은 경우는 컴파일 에러를 일으킨다.

ptr[0]->ShowSon();
ptr[1]->ShowDaughter();

 

Why?

- 포인터의 형이 존재하는 이유는 메모리를 참조하는 기준이 된다. (C에서 포인터를 했을때 확인했던 개념이다.)

- 즉, Son, Daughter의 객체를 참조하는 ptr은 Person의 메모리 크기만을 참조하기 때문이다.

 

 

 

 

오버라이딩(Overriding)

- 부모 클래스의 함수를 자식 클래스가 동일한 이름으로 만들어 해당 함수의 내용을 재정의한다.

#include <iostream>
using namespace std;

class Parent
{
public:
    void SayHello()
    {
        cout << "Parent : 'Hello'" << endl;
    }
};

class Son : public Parent
{
public:
    void SayHello()
    {
        cout << "Son : 'Hello'" << endl;
    }
};

void main()
{
    Parent parent;
    Son son;
    
    parent.SayHello();
    son.SayHello();
    
    //결과
    //Parent : 'Hello'
    //Son : 'Hello'
}
  • 위의 코드를 기준으로 자식 클래스에서 부모 클래스의 함수를 오버라이딩 했다고 해서 업캐스팅으로 자식 클래스의 객체를 참조했을때 오버라이딩 된 함수가 호출되지 않는다.
  • 이유는 업캐스팅 주의사항에서 언급했던 것과 동일하다. 그리고 이러한 문제를 해결해주는게 가상(virtual)함수이다.

 

 

 

 

가상함수(Virtual Function)

- 자식 클래스를 부모 포인터에 업캐스팅 했을 시, 오버라이딩된 함수를 사용하게 해주는 방법

- 부모 클래스에 virtual을 사용해준다.

  • virtual 반환형 함수명 (매개변수)

- 소멸자 함수도 virtual을 사용해 줘야한다. (사용하지 않으면 자식 클래스의 소멸자가 호출되지 않는다.)

#include <iostream>
using namespace std;

class Parent
{
public:
    virtual void SayHello()
    {
        cout << "Parent : 'Hello'" << endl;
    }
    void SayBye()
    {
        cout << "Parent : 'Bye'" << endl;
    }
    virtual ~Parent()
    {
        cout << "Parent Destructor" << endl;
    }
};

class Son : public Parent
{
public:
    void SayHello()
    {
        cout << "Son : 'Hello'" << endl;
    }
    void SayBye()
    {
        cout << "Son : 'Bye'" << endl;
    }
    ~Son()
    {
        cout << "Son Destructor" << endl;
    }
};

void main()
{
    Parent* ptr = new Son();
	
    ptr->SayHello();
    ptr->SayBye();
    delete ptr;
	
    //결과
    //Son : 'Hello'
    //Parent : 'Bye'
    //Son Destructor
    //Parent Destructor
}
  • 동적할당을 해제할 때 부모 클래스의 virtual 유무에 따라 자식 클래스의 소멸자가 호출되는지 확인해보는것도 좋다.

 

※※ 추가 : 멤버, 가상함수의 동작원리

 

C++ 멤버함수, 가상함수 동작원리

멤버함수 동작원리 - C++의 객체의 멤버변수는 객체 내에 존재하지만 멤버함수는 다음과 같은 관계를 갖는다. 멤버함수는 메모리의 한 공간에 별도로 위치한다. 멤버함수가 정의된 클래스의 모

srdeveloper.tistory.com

 

 

반응형

'Stack > C++' 카테고리의 다른 글

C++ 멤버함수, 가상함수 동작원리  (0) 2021.11.17
C++ 순수 가상함수, 추상 클래스  (0) 2021.11.11
C++ 클래스 상속  (0) 2021.11.04
C++ 함수 오버로딩, Deault 매개변수  (0) 2021.10.24
C++ this 포인터  (0) 2021.10.24

+ Recent posts