가상함수
모두의 코드 내용을 공부하고 정리한 내용입니다.
가상 함수
- 가상함수는 파생 클래스에서 재정의할 것으로 기대하는 멤버 함수를 의미
- 이로써 자식 클래스에서 오버라이딩된 함수가 상황에 맞게 호출이 될 수 있다.
- 포인터 또는 기본 클래스에 대한 참조를 이용하여 자식 클래스의 객체를 참조할 때
- 해당 객체에 대해 가상함수를 이용하여 자식 클래스의 멤버함수를 분명하게 사용하려는 목적(아래 예시)
- 이로써 자식 클래스에서 오버라이딩된 함수가 상황에 맞게 호출이 될 수 있다.
가상함수 없다면?
class A
{
public:
void print() { cout << "A" << endl; }
};
class B : public A
{
public:
void print() { cout << "B" << endl; }
};
class C : public B
{
public:
void print() { cout << "C" << endl; }
};
int main()
{
A a;
B b;
C c;
A &ref1 = b;
ref1.print(); // "A" 출력
B &ref2 = c;
ref2.print(); // "B" 출력
}
- 위의 ref1, ref2는 각각 A타입, B타입이기에 b와 c를 가르켜도 A의 print함수, B의 print함수가 호출된다.
가상함수 사용한다면?
class A
{
public:
virtual void print() { cout << "A" << endl; }
};
class B : public A
{
public:
void print() { cout << "B" << endl; }
};
class C : public B
{
public:
void print() { cout << "C" << endl; }
};
int main()
{
A a;
B b;
C c;
A &ref1 = b;
ref1.print(); // "B" 출력
B &ref2 = c;
ref2.print(); // "C" 출력
}
- 가상 함수로 지정된 함수를 호출시 참조하는 객체의 타입이 무엇인가에 따라 호출된다.
- 위의 부모 포인터로 호출하더라도 자식을 가르키기에 자식이 오버라이딩한 함수를 호출한다
- 부모 클래스에서 가상함수를 선언하면 파생 클래스의 재정의된 함수도 자동으로 가상함수가 된다.
- 재정의된 함수에 virtual키워드를 표시해도 안해도 상관없다.
final
- final 키워드를 사용하면 자식 클래스에서 오버라이딩을 못하도록 막아버린다.
class A { public: virtual void print() { cout << "A" << endl; } }; class B : public A { public: void print() final { cout << "B" << endl; } }; class C : public B { public: void print() { cout << "B" << endl; } // 컴파일 오류 };
공변 반환형
class A
{
public:
void print()
{
cout << "A" << endl;
}
virtual A* getThis()
{
cout << "A::getThis()" << endl;
return this;
}
};
class B : public A
{
public:
void print()
{
cout << "B" << endl;
}
virtual B* getThis()
{
cout << "B::getThis()" << endl;
return this;
}
};
- 오버라이딩시 반환형도 같아야하지만 B는 A의 자식이기에 B타입인 B의 this는 A 성질도 있어서
- this를 리턴하는 함수의 경우 리턴 타입이 달라도 오버라이딩이 허용된다.
virtual 소멸자
- 부모 타입의 포인터가 자식 타입의 객체를 참조하고 있을 때 delete를 해주면
- 자식 소멸자는 호출 되지 않고 부모 소멸자만 호출된다.
- 자식을 지우면 (자식 소멸자 -> 부모 소멸자) 순서로 부모 소멸자까지 호출되지만
- 부모를 지우면 부모 소멸자만 호출되어 자식 소멸자는 호출되지 않는다.
- 상속에 있어서 부모는 자식을 포함하지 않으므로…
- 왜 자식 소멸자가 호출 안됨?
- 가상 함수로 정의되지 않은 오버라이딩 함수(소멸자)라서 부모 클래스 소멸자가 호출됨.
- 그래서 소멸자를 가상함수로 만들어주면 해결된다.
- 가상 함수로 정의되지 않은 오버라이딩 함수(소멸자)라서 부모 클래스 소멸자가 호출됨.
상속이 될 또는 상속이 될 거 같은 클래스의 소멸자는 그냥 virtual로 만들자.
개인 공부 기록용 블로그입니다.
틀린 부분 있으다면 지적해주시면 감사하겠습니다!!
댓글남기기