Server 클래스 설계중 virtual 함수에 대한 의문
2023년 7월 16일
의문점 발생 #
Server 클래스 구조 설계를 위해 몇가지 방법을 생각해봤다.
- Server 클래스를 구현 후 IRCServer 클래스에서 상속받기
- SocketServer, IRCServer 를 구현 후 Server 클래스에서 두 클래스를 적절히 사용해서 구현
- IRCManager 클래스를 싱글톤으로 생성한뒤 Server 클래스에서 호출
2번은 프로젝트의 구조로 매력을 못느꼈고, 아마 3번은 다른프로젝트때 써볼 가능성이 있을것같아서 상속구조를 혼자서 생각해보기 위해 1번을 선택하던 중 virtual 함수에 대한 의문이 들었다.
부모 클래스 메소드에서 자식클래스 오버라이딩한 함수를 호출할 수 있나? #
1class Parent {
2public:
3 virtual void Hello() { cout << "Hello P" << endl; }
4 void Test() {
5 cout << "test Function" << endl;
6 Hello(); // 부모클래스의 메소드에서 호출하면 누가 호출될까?
7 }
8};
9
10class Child : public Parent {
11public:
12 virtual void Hello() { cout << "Hello C" << endl; }
13};
14
15int main() {
16 Child a;
17 Parent* p = &a;
18
19 p->Test();
20}
결과는 자식클래스의 함수가 호출된다.
1test Function
2Hello C
그렇다면 자식클래스 메소드에서 오버라이딩한 부모클래스의 함수를 호출할때도 동일한가? #
1class Parent {
2public:
3 virtual void Hello() { cout << "Hello P" << endl; }
4 void Test() { cout << "test Function" << endl; Hello(); }
5};
6
7class Child : public Parent {
8public:
9 virtual void Hello() { cout << "Hello C" << endl; }
10 void Test2() { this->Parent::Test(); }
11};
12
13int main() {
14 Child a;
15
16 a.Test2();
17}
결과는 같다
1test Function
2Hello C
결론 #
사실 이상할것도 없는게 this 포인터를 기준으로 virtual table을 검색하기 때문에, 이미 만들어진 부모의 메소드라 해도 오버라이딩 되어있다면 자식클래스의 메소드가 호출된다.
1 Parent::Hello();
200007FF615B77D7D mov rcx,qword ptr [this]
300007FF615B77D84 call Parent::Hello (07FF615B71744h)
4 }
1 Hello();
200007FF6D4A87D7D mov rax,qword ptr [this]
300007FF6D4A87D84 mov rax,qword ptr [rax]
400007FF6D4A87D87 mov rcx,qword ptr [this]
500007FF6D4A87D8E call qword ptr [rax]
6 }
클래스명을 직접 지정하면 그 함수가 호출되고, 지정하지 않으면 this의 vtable에서 가져온다. 이상한게 둘다 필요없는 this를 한번 더 가져오는 작업이 있다.
채택한 방법 #
Server 클래스를 구현 후 IRCServer 클래스에서 상속받기 #
Server 클래스에서는 브로드캐스팅이나 메시지 반사 기능을 수행하는 Execute 함수를 구현하고, Execute를 Run에서 실행시킨다.
IRCServer 클래스는 Server 클래스를 상속받은 후 Execute 함수만 오버라이딩 한다.
아마 맞물려서 정상적으로 동작할것이라고 예상할 수 있다.
-> 정리 필요