[C++] Virtual Function

가상 함수

가상함수는 런타임에 클래스의 다형성을 구성하기 위해 사용한다. 자식 클래스에서 부모 클래스의 함수를 재정의하지 않을 시 부모 클래스의 함수를 호출한다. 상속관계에서 is-A 관계로 부모 클래스 자료형에 자식 클래스를 할당했을 때 자식 클래스에서 오버라이딩한 함수가 있다 해도 포인터는 자료형을 기준으로 판단하기 때문에 부모 클래스의 함수를 호출한다. 이를 방지하기 위해 가상 함수를 사용한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;
class A{
public:
void pA(){ cout<<"AA function"<<endl; }
virtual void pB(){ cout<<"AB function"<<endl; }
};
class B : public A{
public:
void pA() { cout<<"BA function"<<endl; }
void pB() override { cout<<"BB function"<<endl; }
};
int main() {
A *a = new B;
a->pA(); //AA
a->pB(); //BB
B *b = new B;
b->pA(); //BA
b->pB(); //BB
}

순수 가상 함수

자식 클래스에서 반드시 재정의가 필요한 가상 함수이다. virtual 키워드만 멤버로 가질 수 있다. 개발자에게 해당 클래스의 구현을 강제할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
using namespace std;

class A{
public :
virtual void virtual_function(){ printf("This is virtual function A\n"); }
void nomal_function() { printf("This is normal function A\n"); }
A() { printf("CREATE A\n"); }
virtual void pure_virtual() = 0;
virtual ~A() { printf("DESTROY A\n"); }
};
class B : public A{
public:
virtual void virtual_function() { printf("This is virtual function B\n"); }
void normal_function() { printf("This is normal function B\n"); };
B() { printf("CREATE B\n"); }
virtual void pure_virtual() { printf("This is Pure virtual function()"); }
virtual ~B() { printf("DESTROY B\n"); }
};
int main(int argc, char** argv){
// A *a = new A;
A *b = new B;
// a->nomal_function();
b->nomal_function();
// a->virtual_function();
b->virtual_function();
b->pure_virtual();
// delete a;
delete b;
}

가상 함수 테이블

클래스 내에 가상함수가 존재한다면 실제 객체가 가상함수를 실행할 때 어떤 주소의 함수를 실행시킬지에 대한 정보를 담은 테이블이다. 가상 함수 테이블은 클래스별로 생성된다.

가상 소멸자

자식 클래스를 소멸시킬 때 부모 클래스의 소멸자가 가상 소멸자가 아니라면 부모 클래스의 소멸자만 호출되고 memory leak이 일어난다. 이를 방지하기 위해 부모 클래스의 소멸자를 가상 소멸자로 지정하고 자식 클래스에서 소멸자를 선언해 자식 클래스도 소멸시켜야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//
// Created by SummerFlower on 31/05/2020.
//

#ifndef C__STUDY_VIRTUALCLASS_H
#define C__STUDY_VIRTUALCLASS_H

#endif //C__STUDY_VIRTUALCLASS_H
#include <iostream>
using namespace std;
namespace VirtualClass {
class A {
public:
A() { cout << "A 생성자" << endl; }

~A() { cout << "A 소멸자" << endl; }

void f() { cout << "A function" << endl; }
};

class B : public A {
public:
B() { cout << "B 생성자" << endl; }

~B() { cout << "B 소멸자" << endl; }

void f() { cout << "B function" << endl; }
};

class AA {
public:
AA() { cout << "AA 생성자" << endl; }

virtual ~AA() { cout << "AA 소멸자" << endl; }

virtual void f() { cout << "AA function" << endl; }
};

class BB : public AA {
public:
BB() { cout << "BB 생성자" << endl; }

~BB() override { cout << "BB 소멸자" << endl; }

void f() override { cout << "BB function" << endl; }
};

void castingOperator() {
B *b = new B();
A *a = dynamic_cast<A *>(b);
a->f();
b->f();

A *prime_a = new B();
//B *prime_b = dynamic_cast<B*>(prime_a); //impossible;
B *prime_b = static_cast<B *>(prime_a);
prime_a->f();
prime_b->f();

AA *aa = new BB();
BB *bb = dynamic_cast<BB *>(aa);
aa->f();
bb->f();

delete a;
delete prime_a;
delete aa;
}

void VirtualClassStudy() {
A *b = new B();
b->f();
AA *bb = new BB();
bb->f();

delete b;
delete bb;
}
}
Author: Song Hayoung
Link: https://songhayoung.github.io/2020/08/03/Languages/Cplusplus/virtual-function/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.