C++ 상속 오버라이딩 및 가상함수
- 상속 오버라이딩 (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();
}
로 사용할 수 있다.
- 가상 함수 (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 선언한 부분이 자동으로 선언되지만
코드의 이해를 돕기 위해 써주는 것이 좋다.
-
순수 가상 함수 (Pure virtual Function)
– 부모 클래스의 function 부분 내용을 선언하지 않고 virtual void function() = 0; 으로 초기화 한 함수.
– 순수 가상 함수를 포함하는 클래스를 추상 클래스(abstract class)라 한다.
– 순수 가상 함수는 반드시 자식 클래스에서 오버라이딩 되어야 한다. -
다중 상속 (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를 자식 클래스에 상속
단, 다중 상속은 상속 받은 두 클래스에서 같은 이름의 함수가 있을 경우 실행의 모호성 등이 발생하므로 다중 상속에 대한 정확한 이해가 없다면 가급적 사용하지 않길 권장
해결법 : 범위 지정 연산자, 다이아몬드 상속 참고