Lasiyan
Code

C++ 상속 오버라이딩 및 가상함수

#C++#상속#오버라이딩#가상 함수
  1. 상속 오버라이딩 (Inheritance Overriding)
    오버로딩 : 인자의 자료형이나 수가 다른 함수를 같은 이름으로 여러번 중복 정의하는 것

오버라이딩 : 이미 있는 함수를 무시해버리고 새롭게 함수를 재정의 하는 것
– 부모 클래스와 자식 클래스의 상속 관계에서 부모 클래스에 이미 정의된 함수를 같은 이름으로 자식 클래스에서 재정의 하는 것을 의미.
– 이 때, 부모의 멤버 함수와 원형이 완전이 같아야 한다.
– 또한 오버라이딩 시 부모 클래스의 함수가 모두 가려진다는 점을 유의.

#include <iostream>

using namespace std;

class parent {
public:
    void print() {
        cout << "부모 클래스의 print 함수" << endl;
    }
};

class child : public parent {
public:
    void print() {
        cout << "자식 클래스의 print 함수" << endl;
    }
};

void main() {
    child c;
    c.print();
}

위의 코드에서 자식 클래스에서 print 함수를 오버라이딩 하여 main() 함수에서 부모 클래스 print 함수 대신 자식 클래스 print 함수가 출력됨을 볼 수 있다.

부모 클래스의 print 함수를 사용하고 싶을 경우
자식 클래스의 print 부분에서 네임스페이스를 이용하여

void print() {
    parent::print();
    cout << "자식 클래스의 print 함수" << endl;
}

와 같이 사용하거나 메인함수에서 별도로 parent 클래스를 선언하여

void main() {
    child c;
    parent p;
    p.print();
    c.print();
}

로 사용할 수 있다.

  1. 가상 함수 (Virtual Function)
    포인터 사용 시 C++ 컴파일러가 실제로 가리키는 객체의 자료형을 기준으로 하는게 아닌, 포인터 변수의 자료형을 기준으로 판단하기 때문에 실제로 가리키는 객체의 자료형에 따라 멤버 변수가 호출되도록 설정하기 위해서 사용
#include <iostream>

using namespace std;

class parent {
public:
    void print() {
        cout << "부모 클래스의 print 함수" << endl;
    }
};
class child : public parent {
public:
    void print() {
        cout << "자식 클래스의 print 함수" << endl;
    }
};

void main() {
    parent p;
    parent* pp;
    child c;

    /* 1. parent 클래스 포인터 pp에 parent 클래스 p 지정 */
    pp = &p;
    pp->print();
    // 정상적으로 parent 클래스의 print 함수 출력

    /* 2. parent 클래스 포인터 pp에 child 클래스 c 지정 */
    pp = &c;
    pp->print();
    // child 클래스의 print 함수가 출력될 줄 알았으나
    // parent 클래스의 print 함수가 출력
    // 원인 : C++ 컴파일러는 포인터 변수의 자료형을 기준으로 판단.
    // 따라서 이것을 실제로 가르키는 객체의 자료형(child)로 판단하도록
    // 변경이 필요하다. = 가상 함수 사용 목적

    /* 3. parent 클래스 포인터 pp에 child 클래스 c 지정
          단, 각 클래스 print에 가상 함수 지정
    */
    // parent 클래스의 void print() { ... } 부분을
    // virtual void print() { ... } 로 변경 후 실행
    // child 클래스의 void print() { ... } 부분을
    // virtual void print() { ... } 로 변경 후 실행
}

3번의 경우 실제로 부모 클래스에 virtual 선언을 하면
상속을 받은 자식 클래스에도 virtual 선언한 부분이 자동으로 선언되지만
코드의 이해를 돕기 위해 써주는 것이 좋다.

  1. 순수 가상 함수 (Pure virtual Function)
    – 부모 클래스의 function 부분 내용을 선언하지 않고 virtual void function() = 0; 으로 초기화 한 함수.
    – 순수 가상 함수를 포함하는 클래스를 추상 클래스(abstract class)라 한다.
    – 순수 가상 함수는 반드시 자식 클래스에서 오버라이딩 되어야 한다.

  2. 다중 상속 (Multiple Inheritance)
    둘 이상의 클래스를 동시에 상속하는 것.

#include <iostream>

using namespace std;

class parent1 {
public:
    virtual void print1() {
        cout << "부모 클래스 1 의 print 함수" << endl;
    }
};
class parent2 {
public:
    virtual void print2() {
        cout << "부모 클래스 2 의 print 함수" << endl;
    }
};

// parent 클래스 1과 2 다중 상속
class child : public parent1, public parent2 {
public:
    void print() {
        print1();
        print2();
        cout << "자식 클래스의 print 함수" << endl;
    }
};

void main() {
    child c;

    c.print();
}

콤마(,)를 사용하여 부모 클래스 1과 2를 자식 클래스에 상속

단, 다중 상속은 상속 받은 두 클래스에서 같은 이름의 함수가 있을 경우 실행의 모호성 등이 발생하므로 다중 상속에 대한 정확한 이해가 없다면 가급적 사용하지 않길 권장

해결법 : 범위 지정 연산자, 다이아몬드 상속 참고