๐ 04/23 โ vtable ์ฌํ (๋ชจ์๋ฉด์ ๋ฏธ๋ต๋ณ ๋ณต๊ธฐ)
์ค๋ ๋ชจ์๋ฉด์ ์์ ๋งํ ์ง๋ฌธ๋ค์ ์ ๋ฆฌํ ์ฌํ ํ์ผ ๊ธฐ๋ณธ ๊ฐ๋
์ โ 05_vtable.md
๋ชฉ์ฐจ
- vtable ๋จ์
- vtable์ ๊ฐ์ฒด๋ง๋ค? ํด๋์ค๋ง๋ค?
- ์์ ๊ฐ์ ํจ์์ _purecall
- ์์ override ํจ์๊ฐ vtable ๋ฐฐ์ด ์์์ ์ด๋ป๊ฒ ๋์ํ๋
- override๊ฐ ์๋ ๊ฒฝ์ฐ vtable ์ฌ๋กฏ์?
- virtual ์ ์ธ ์ vtable๊ณผ ํจ๊ป ์์ฑ๋๋ RTTI
- ์ธ๋ฆฌ์ผ์์ SetPurecallHandler
1. vtable ๋จ์
Q: โvtable์ ์ฌ์ฉํ๋ฉด ์ด๋ค ๋จ์ ์ด ์๋์?โ
๋จ์ 4๊ฐ์ง
| ๋จ์ | ์ค๋ช
| ํฌ๊ธฐ |
|---|
| ๋ฉ๋ชจ๋ฆฌ ์ค๋ฒํค๋ | ๊ฐ์ฒด๋ง๋ค vptr 8๋ฐ์ดํธ ์ถ๊ฐ | ๋ฎ์ |
| ๊ฐ์ ํธ์ถ ๋น์ฉ | vptr โ vtable โ ํจ์ํฌ์ธํฐ, ์ญ์ฐธ์กฐ 2๋ฒ | ์ค๊ฐ |
| ์ธ๋ผ์ด๋ ๋ถ๊ฐ | ์ปดํ์ผ ํ์์ ์ด๋ค ํจ์ ํธ์ถ๋ ์ง ๋ชจ๋ฆ โ ์ธ๋ผ์ธ ์ต์ ํ ์ฐจ๋จ | ๋์ |
| ์บ์ ๋ฏธ์ค | vtable์ด .rodata์ ์์ด ์บ์ ์๋ฐ์ด ์ ๋ ๊ฒฝ์ฐ ์บ์ ๋ฏธ์ค | ์ค๊ฐ~๋์ |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // ์ธ๋ผ์ด๋ ๋ถ๊ฐ ์์
class Shape {
public:
virtual void Draw() { } // ์ปดํ์ผ๋ฌ๊ฐ ์ธ๋ผ์ธ ๋ถ๊ฐ
};
// CRTP๋ก ์ธ๋ผ์ด๋ ๊ฐ๋ฅํ๊ฒ ๋ณํ
template<typename Derived>
class ShapeBase {
public:
void Draw() {
static_cast<Derived*>(this)->DrawImpl(); // ์ปดํ์ผ ํ์ ๊ฒฐ์ โ ์ธ๋ผ์ธ ๊ฐ๋ฅ
}
};
|
์ถ๊ฐ ๋จ์ : ์์ฑ์/์๋ฉธ์ ๋ด๋ถ ๊ฐ์ ํจ์ ํธ์ถ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| class Base {
public:
Base() { Foo(); } // ์ํ! ์ด ์์ ์ vptr์ Base::vtable
virtual void Foo() { std::cout << "Base::Foo\n"; }
};
class Derived : public Base {
public:
void Foo() override { std::cout << "Derived::Foo\n"; }
};
Derived d; // "Base::Foo" ์ถ๋ ฅ โ Derived::Foo๊ฐ ์๋!
// ์ด์ : Base ์์ฑ์ ์คํ ์์ ์ vptr = &Base::vtable
// Derived ์์ฑ์ ์คํ ํ์์ผ vptr = &Derived::vtable
|
30์ด ๋ต๋ณ:
vtable์ ๋จ์ ์ ์ธ ๊ฐ์ง์
๋๋ค. ์ฒซ์งธ, ๊ฐ์ ํธ์ถ ๋น์ฉ โ vptr์์ vtable, vtable์์ ํจ์ ํฌ์ธํฐ๊น์ง ์ญ์ฐธ์กฐ๊ฐ 2๋ฒ ๋ฐ์ํฉ๋๋ค. ๋์งธ, ์ปดํ์ผ ํ์์ ํธ์ถ ํจ์๋ฅผ ํน์ ํ ์ ์์ด ์ธ๋ผ์ธ ์ต์ ํ๊ฐ ๋ถ๊ฐ๋ฅํฉ๋๋ค. ์
์งธ, vtable ํฌ์ธํฐ ์ญ์ฐธ์กฐ ์ ์บ์ ๋ฏธ์ค๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ฑ๋ฅ์ด ์ค์ํ Hot Path๋ผ๋ฉด final ํค์๋๋ก devirtualizeํ๊ฑฐ๋ CRTP๋ฅผ ์ฌ์ฉํฉ๋๋ค.
2. vtable์ ๊ฐ์ฒด๋ง๋ค? ํด๋์ค๋ง๋ค?
Q: โvtable์ ๊ฐ์ฒด๋ง๋ค ์์ฑ๋๋์, ํด๋์ค๋ง๋ค ์์ฑ๋๋์?โ
ํต์ฌ ๊ตฌ๋ถ
1
2
| vtable โ ํด๋์ค๋ง๋ค 1๊ฐ (์ปดํ์ผ ํ์ ์์ฑ, .rodata ์ฝ๊ธฐ ์ ์ฉ ์์ญ)
vptr โ ๊ฐ์ฒด๋ง๋ค 1๊ฐ (๋ฐํ์, ์์ฑ์ ํธ์ถ ์ ์ด๊ธฐํ)
|
1
2
3
4
5
6
7
8
9
10
| class Animal {
public:
virtual void Speak() { }
};
Animal a1, a2, a3;
// vtable: Animal::vtable ๋ฑ 1๊ฐ โ ์ธ ๊ฐ์ฒด๊ฐ ๊ณต์
// vptr: a1.vptr, a2.vptr, a3.vptr ๊ฐ๊ฐ ์กด์ฌ
// (๋ชจ๋ ๊ฐ์ Animal::vtable์ ๊ฐ๋ฆฌํด)
|
1
2
3
4
5
6
7
8
| ๋ฉ๋ชจ๋ฆฌ ๊ตฌ์กฐ:
a1: [ vptr โ Animal::vtable ] [ ๋ฉค๋ฒ ๋ณ์ ]
a2: [ vptr โ Animal::vtable ] [ ๋ฉค๋ฒ ๋ณ์ ] โ ๊ฐ์ vtable ๊ฐ๋ฆฌํด
a3: [ vptr โ Animal::vtable ] [ ๋ฉค๋ฒ ๋ณ์ ]
Animal::vtable (์ฝ๊ธฐ ์ ์ฉ, .rodata):
[ &Animal::Speak, &Animal::~Animal ]
|
์ ํด๋์ค๋น 1๊ฐ์ธ๊ฐ?
vtable์ ๋ด์ฉ(ํจ์ ํฌ์ธํฐ ๋ฐฐ์ด)์ ๋ชจ๋ ๊ฐ์ฒด์์ ๋์ผํ๊ธฐ ๋๋ฌธ์ ๊ณต์ ํด๋ ์์ ํฉ๋๋ค. ๊ฐ์ฒด๋ณ๋ก ๋ฌ๋ผ์ง๋ ๊ฒ์ vptr์ด ๊ฐ๋ฆฌํค๋ ๋์(์ด๋ค ํด๋์ค์ vtable์ธ์ง)์ด์ง, vtable ์์ฒด์ ๋ด์ฉ์ด ์๋๋๋ค.
30์ด ๋ต๋ณ:
vtable์ ํด๋์ค๋ง๋ค 1๊ฐ ์์ฑ๋ฉ๋๋ค. ์ปดํ์ผ ํ์์ ๋ง๋ค์ด์ ธ ์ฝ๊ธฐ ์ ์ฉ ๋ฉ๋ชจ๋ฆฌ(.rodata)์ ์ ์ฅ๋ฉ๋๋ค. ๋ฐ๋ฉด vptr์ ๊ฐ์ฒด๋ง๋ค 1๊ฐ์ฉ ์กด์ฌํ๋ฉฐ, ์์ฑ์ ํธ์ถ ์ ๋ฐํ์์ ํด๋น ํด๋์ค์ vtable ์ฃผ์๋ก ์ด๊ธฐํ๋ฉ๋๋ค. ๊ฐ์ ํด๋์ค์ ๋ชจ๋ ๊ฐ์ฒด๋ ๋์ผํ vtable์ ๊ณต์ ํฉ๋๋ค.
3. ์์ ๊ฐ์ ํจ์์ _purecall
Q: โ์์ ๊ฐ์ ํจ์๋ vtable์์ ์ด๋ป๊ฒ ์ฒ๋ฆฌ๋๋์? ํธ์ถํ๋ฉด ์ด๋ป๊ฒ ๋ฉ๋๊น?โ
์์ ๊ฐ์ ํจ์ ์ ์ธ
1
2
3
4
5
| class IShape {
public:
virtual void Draw() = 0; // ์์ ๊ฐ์ ํจ์
virtual ~IShape() = default;
};
|
= 0 ์ ์ธ โ ์ด ํด๋์ค๋ ์ถ์ ํด๋์ค(instantiation ๋ถ๊ฐ)- vtable ์ฌ๋กฏ์๋
__cxa_pure_virtual (GCC/Clang) ๋๋ _purecall (MSVC) ํจ์ ํฌ์ธํฐ ๋ฑ๋ก
_purecall ๋ฐ์ ์๋๋ฆฌ์ค
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class Base {
public:
virtual void Foo() = 0;
Base() {
Foo(); // UB! ์์ฑ์ ์์์ ์์ ๊ฐ์ ํจ์ ํธ์ถ
// vptr์ด ์์ง Base::vtable โ _purecall ํธ์ถ โ ํ๋ก๊ทธ๋จ ์ข
๋ฃ
}
};
class Derived : public Base {
public:
void Foo() override { }
};
Derived d; // Base() ์์ฑ์์์ _purecall ํธ์ถ๋จ
|
_purecall ๋์:
- ์์ ๊ฐ์ ํจ์ ํธ์ถ ๊ฐ์ง
- MSVC CRT์
_purecall() ํจ์ ์คํ - ๊ธฐ๋ณธ ๋์:
abort() โ ํ๋ก๊ทธ๋จ ์ฆ์ ์ข
๋ฃ
_set_purecall_handler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| #include <stdlib.h>
// ์ปค์คํ
ํธ๋ค๋ฌ โ ๋๋ฒ๊น
/๋ก๊น
๋ชฉ์
void MyPureCallHandler() {
// ์คํ ํธ๋ ์ด์ค ์ถ๋ ฅ, ํฌ๋์ ๋ฆฌํฌํธ ์ ์ก ๋ฑ
std::cerr << "[FATAL] ์์ ๊ฐ์ ํจ์ ํธ์ถ ๊ฐ์ง!\n";
// ๋ฐํํ์ง ๋ง ๊ฒ โ ๋ฐํํ๋ฉด UB
abort();
}
int main() {
_set_purecall_handler(MyPureCallHandler);
// ์ดํ _purecall ๋ฐ์ ์ MyPureCallHandler ํธ์ถ
}
|
_set_purecall_handler๋ก ์ปค์คํ
ํธ๋ค๋ฌ ๊ต์ฒด ๊ฐ๋ฅ- ํธ๋ค๋ฌ๋ ๋ฐ๋์ ์ข
๋ฃํด์ผ ํจ (๋ฐํ ์ Undefined Behavior)
- ๋๋ฒ๊ทธ ๋น๋์์ ์ฝ์คํ ๋คํ, ํฌ๋์ ๋ฆฌํฌํฐ ์ฐ๋์ ํ์ฉ
4. ์์ override ํจ์๊ฐ vtable ๋ฐฐ์ด ์์์ ์ด๋ป๊ฒ ๋์ํ๋
Q: โ์์ ํด๋์ค์์ overrideํ ํจ์๊ฐ vtable ๋ฐฐ์ด ์์์ ์ด๋ป๊ฒ ์ฒ๋ฆฌ๋ฉ๋๊น?โ
์ฌ๋กฏ ๊ต์ฒด ๋ฉ์ปค๋์ฆ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| class Animal {
public:
virtual void Speak() { } // ์ฌ๋กฏ [0]
virtual void Move() { } // ์ฌ๋กฏ [1]
virtual ~Animal() { } // ์ฌ๋กฏ [2]
};
class Dog : public Animal {
public:
void Speak() override { } // ์ฌ๋กฏ [0] ๊ต์ฒด
// Move()๋ override ์ ํจ
};
// Animal vtable: [ &Animal::Speak, &Animal::Move, &Animal::~Animal ]
// Dog vtable: [ &Dog::Speak, &Animal::Move, &Dog::~Dog ]
// ^^^^^^^^^^^^โ ์ฌ๋กฏ [0]๋ง ๊ต์ฒด๋จ
|
๋ฐํ์ ํธ์ถ ํ๋ฆ
1
2
3
4
5
6
7
8
9
10
11
12
| Animal* a = new Dog();
a->Speak();
1. a๊ฐ ๊ฐ๋ฆฌํค๋ ๊ฐ์ฒด์ vptr ์ฝ๊ธฐ โ Dog::vtable ์ฃผ์
2. Dog::vtable[0] ์ฝ๊ธฐ โ &Dog::Speak
3. Dog::Speak() ํธ์ถ โ ์ฌ๋ฐ๋ฅธ ์์ ํจ์!
a->Move();
1. a์ vptr ์ฝ๊ธฐ โ Dog::vtable ์ฃผ์
2. Dog::vtable[1] ์ฝ๊ธฐ โ &Animal::Move (๋ณต์ฌ๋ ํฌ์ธํฐ)
3. Animal::Move() ํธ์ถ
|
ํต์ฌ: ์ฌ๋กฏ ์ธ๋ฑ์ค๋ ์์ ๊ณ์ธต ์ ๋ฐ์์ ๋์ผํ๊ฒ ์ ์ง๋ฉ๋๋ค. ์ปดํ์ผ๋ฌ๋ virtual void Speak()๊ฐ ํญ์ ์ฌ๋กฏ [0]์์ ์๊ณ ์์ผ๋ฏ๋ก, ํฌ์ธํฐ ํ์
์ด ๋ฌด์์ด๋ ๊ฐ์ ์คํ์
์ผ๋ก ์ ๊ทผํฉ๋๋ค.
5. override๊ฐ ์๋ ๊ฒฝ์ฐ vtable ์ฌ๋กฏ์?
Q: โ์์ ํด๋์ค์์ overrideํ์ง ์์ ๊ฐ์ ํจ์๋ ์ด๋ป๊ฒ ๋ฉ๋๊น?โ
๋ถ๋ชจ ํจ์ ํฌ์ธํฐ ๊ทธ๋๋ก ๋ณต์ฌ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class Animal {
public:
virtual void Speak() { std::cout << "...\n"; }
virtual void Move() { std::cout << "์ด๋\n"; }
};
class Dog : public Animal {
public:
void Speak() override { std::cout << "๋ฉ๋ฉ\n"; }
// Move()๋ override ์ ํจ
};
Animal* a = new Dog();
a->Move(); // Animal::Move() ํธ์ถ
// Dog vtable์ [1] = &Animal::Move (๋ณต์ฌ๋ ํฌ์ธํฐ์ด๋ฏ๋ก)
|
1
2
3
4
5
6
7
| Dog vtable ์์ฑ ๊ณผ์ :
1. Animal vtable์ ๊ทธ๋๋ก ๋ณต์ฌ:
[ &Animal::Speak, &Animal::Move, &Animal::~Animal ]
2. override๋ ์ฌ๋กฏ๋ง ๊ต์ฒด:
[ &Dog::Speak, &Animal::Move, &Dog::~Dog ]
^^^^^^^^^^^^โ ๊ต์ฒด ์์, ๋ถ๋ชจ ๊ฒ ๊ทธ๋๋ก
|
๊ฒฐ๊ณผ: Dog ๊ฐ์ฒด์์ Move()๋ฅผ ํธ์ถํด๋ Animal::Move()๊ฐ ์คํ๋ฉ๋๋ค. ์ฌ๋กฏ์ ๋ถ๋ชจ ํจ์ ํฌ์ธํฐ๊ฐ ๋ณต์ฌ๋์ด ์๊ธฐ ๋๋ฌธ์
๋๋ค.
30์ด ๋ต๋ณ:
์์ ํด๋์ค๊ฐ ๊ฐ์ ํจ์๋ฅผ overrideํ์ง ์์ผ๋ฉด, ์์์ vtable์๋ ๋ถ๋ชจ์ ํจ์ ํฌ์ธํฐ๊ฐ ๊ทธ๋๋ก ๋ณต์ฌ๋ฉ๋๋ค. ๋ฐ๋ผ์ ์์ ๊ฐ์ฒด๋ฅผ ๋ถ๋ชจ ํฌ์ธํฐ๋ก ๊ฐ๋ฆฌํค๊ณ ํด๋น ํจ์๋ฅผ ํธ์ถํด๋ ๋ถ๋ชจ์ ๊ตฌํ์ด ์คํ๋ฉ๋๋ค.
6. virtual ์ ์ธ ์ vtable๊ณผ ํจ๊ป ์์ฑ๋๋ RTTI
Q: โvirtual ํค์๋๋ฅผ ์ฐ๋ฉด vtable ์์ฑ๊ณผ ํจ๊ป RTTI๋ ์์ฑ๋๋์?โ
vtable์ ์ค์ ๊ตฌ์กฐ (์จ๊ฒจ์ง ํค๋ ํฌํจ)
1
2
3
4
5
6
7
8
9
10
| vtable ๋ฉ๋ชจ๋ฆฌ ๋ ์ด์์ (GCC/Clang ABI ๊ธฐ์ค):
[ type_info* ] โ RTTI ์ ๋ณด ํฌ์ธํฐ (vtable[-1])
[ offset_to_top] โ ๋ค์ค ์์์ฉ ์คํ์
(vtable[-2])
[ Func1* ] โ ๊ฐ์ ํจ์ ํฌ์ธํฐ [0]
[ Func2* ] โ ๊ฐ์ ํจ์ ํฌ์ธํฐ [1]
[ ... ]
vptr๋ Func1* ์์น๋ฅผ ๊ฐ๋ฆฌํด
RTTI๋ vptr[-1]๋ก ์ ๊ทผ
|
1
2
3
4
5
6
7
8
9
10
11
12
| class Animal {
public:
virtual void Speak() { } // virtual ํ๋๋ง ์์ด๋ RTTI ์๋ ์์ฑ
};
Animal* a = new Dog();
// typeid ์ฌ์ฉ โ ๋ด๋ถ์ ์ผ๋ก vptr[-1]์ type_info ์ ๊ทผ
std::cout << typeid(*a).name(); // "Dog" ์ถ๋ ฅ
// dynamic_cast๋ RTTI ์ฌ์ฉ
Dog* d = dynamic_cast<Dog*>(a); // vtable์ type_info๋ก ํ์
ํ์ธ
|
RTTI ์์ฑ ์กฐ๊ฑด
| ์กฐ๊ฑด | RTTI ์์ฑ ์ฌ๋ถ |
|---|
virtual ํจ์ ์์ | ์์ฑ ์ ๋จ |
virtual ํจ์ 1๊ฐ ์ด์ | ์๋ ์์ฑ |
-fno-rtti ์ปดํ์ผ ํ๋๊ทธ | ๋ช
์์ ์ผ๋ก ๋นํ์ฑํ |
1
2
3
4
5
6
7
8
9
10
| class Plain { // virtual ์์ โ RTTI ์์
int x;
};
class Base { // virtual ์์ โ RTTI ์๋ ์์ฑ
virtual void Foo() { }
};
// typeid(Plain{}) โ ์ ์ RTTI (์ปดํ์ผ ํ์, vtable ๋ถํ์)
// typeid(*base_ptr) โ ๋์ RTTI (๋ฐํ์, vtable ํ์)
|
30์ด ๋ต๋ณ:
virtual ํค์๋๋ฅผ ์ฌ์ฉํ๋ฉด ์ปดํ์ผ๋ฌ๋ vtable์ ์์ฑํ๋ฉด์ type_info ํฌ์ธํฐ๋ ํจ๊ป vtable ํค๋์ ์ฌ์ต๋๋ค. typeid(*ptr)๋ dynamic_cast๋ฅผ ํธ์ถํ๋ฉด vptr์ ํตํด ์ด type_info์ ์ ๊ทผํ์ฌ ๋ฐํ์ ํ์
์ ํ์ธํฉ๋๋ค. ์ฆ RTTI๋ vtable์ด ์์ด์ผ๋ง ๋์ํ๋ ๋์ ํ์
์ ๋ณด ์์คํ
์
๋๋ค.
7. ์ธ๋ฆฌ์ผ์์ SetPurecallHandler
Q: โ์ธ๋ฆฌ์ผ ์์ง์์ SetPurecallHandler๋ ๋ฌด์์ธ๊ฐ์?โ
์ธ๋ฆฌ์ผ์ ์์ง ์ด๊ธฐํ ์ _set_purecall_handler๋ฅผ ์ด์ฉํด ์ปค์คํ
ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํฉ๋๋ค. ์์ ๊ฐ์ ํจ์ ํธ์ถ(๊ฐ๋ฐ ์ค ์ค์)์ ์์ง ํฌ๋์ ๋ฆฌํฌํฐ์ ์ฐ๋ํ๊ธฐ ์ํด์์
๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
| // ์ธ๋ฆฌ์ผ ์์ง ๋ด๋ถ (Windows ํ๋ซํผ)
// UnrealEngine/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformCrashContext.cpp
static void PureCallHandler() {
// 1. ์ฝ์คํ ์บก์ฒ
// 2. ํฌ๋์ ๋ฆฌํฌํฐ๋ก ์ ์ก
// 3. ์๋ํฐ๋ฉด ๋ฉ์์ง ๋ฐ์ค ํ์
UE_LOG(LogCore, Fatal, TEXT("Pure virtual function called"));
// โ FPlatformMisc::RaiseException ํธ์ถ โ ํฌ๋์ ๋ค์ด์ผ๋ก๊ทธ
}
// ์์ง ์์ ์:
_set_purecall_handler(PureCallHandler);
|
์ค์ ๋ก ๋ง์ฃผ์น๋ ์ํฉ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // ์ธ๋ฆฌ์ผ์์ ์์ฃผ ๋ฐ์ํ๋ ์ผ์ด์ค:
// ์์ฑ์์์ ์์ ๊ฐ์ ํจ์ ํธ์ถ (vtable์ด ์์ฑ๋๊ธฐ ์ )
UCLASS()
class AMyActor : public AActor {
GENERATED_BODY()
public:
AMyActor() {
InitData(); // ๋ง์ฝ InitData๊ฐ ์์ ๊ฐ์์ด๋ผ๋ฉด โ purecall!
}
virtual void InitData() = 0; // ์์ ๊ฐ์
};
// ์๋ฌ ๋ฉ์์ง:
// "Pure virtual function called" + ํฌ๋์ ๋ฆฌํฌํฐ ํ์
|
์ค๋ฌด ํ: ์ธ๋ฆฌ์ผ์์ ์ด ์ค๋ฅ๋ฅผ ๋ณด๋ฉด ์์ฑ์ ๋ด ๊ฐ์ ํจ์ ํธ์ถ ์ฌ๋ถ ๋จผ์ ํ์ธ.
ํด๊ฒฐ์ฑ
: ์์ฑ์ ๋์ BeginPlay()๋ PostInitializeComponents()์์ ์ด๊ธฐํ.
ํต์ฌ ์์ฝ (30์ด ๋ต๋ณ ์นด๋)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| vtable ๋จ์ :
๊ฐ์ ํธ์ถ(์ญ์ฐธ์กฐ 2๋ฒ) + ์ธ๋ผ์ด๋ ๋ถ๊ฐ + ์บ์ ๋ฏธ์ค
โ Hot Path: final(devirtualize) ๋๋ CRTP
vtable vs vptr:
vtable = ํด๋์ค๋น 1๊ฐ (์ปดํ์ผ ํ์, .rodata)
vptr = ๊ฐ์ฒด๋น 1๊ฐ (๋ฐํ์, ์์ฑ์์์ ์ด๊ธฐํ)
์์ ๊ฐ์ + purecall:
= 0 ์ ์ธ โ vtable ์ฌ๋กฏ์ _purecall ๋ฑ๋ก
ํธ์ถ ์ ํ๋ก๊ทธ๋จ ์ข
๋ฃ (_set_purecall_handler๋ก ์ปค์คํ
๊ฐ๋ฅ)
override ์๋ ์ฌ๋กฏ:
๋ถ๋ชจ ํจ์ ํฌ์ธํฐ ๊ทธ๋๋ก ๋ณต์ฌ โ ๋ถ๋ชจ ๊ตฌํ ์คํ
vtable + RTTI:
virtual ์์ผ๋ฉด type_info* ๊ฐ vtable ํค๋์ ์๋ ์์ฑ
typeid / dynamic_cast = vtable[-1] ์ ๊ทผ
|
์ฐธ๊ณ