function을 virtual로 선언해도 non-virtual call로 실행되는 경우도 있네요.




[Source]

  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. struct Obj {
  6. void fooA() { cout << "Obj::fooA\n"; }
  7. void fooB() { cout << "Obj::fooB\n"; }
  8. void fooC() { cout << "Obj::fooC\n"; }
  9. virtual void vfooA() { cout << "Obj::vfooA\n"; }
  10. virtual void vfooB() { cout << "Obj::vfooB\n"; }
  11. virtual void vfooC() { cout << "Obj::vfooC\n"; }
  12. };
  13.  
  14. void test1(Obj obj) {
  15. obj.fooA();
  16. obj.fooB();
  17. obj.fooC();
  18. // mov -0x8(%rbp),%rax ;
  19. // mov %rax,%rdi ; rdi에 obj 포인터 값 넣음
  20. // callq 0x561805916ab8 <Obj::fooC()> ; non-virtual call
  21. obj.vfooA();
  22. obj.vfooB();
  23. obj.vfooC();
  24. // mov -0x8(%rbp),%rax ;
  25. // mov %rax,%rdi ; rdi에 obj 포인터 값 넣음
  26. // callq 0x561805916b2a <Obj::vfooC()> ; non-virtual call
  27. }
  28.  
  29. void test2(Obj* obj) {
  30. obj->fooA();
  31. obj->fooB();
  32. obj->fooC();
  33. // mov -0x8(%rbp),%rax ;
  34. // mov %rax,%rdi ; rdi에 obj 포인터 값 넣음
  35. // callq 0x561805916ab8 <Obj::fooC()> ; non-virtual call
  36. obj->vfooA();
  37. obj->vfooB();
  38. obj->vfooC);
  39. // mov -0x8(%rbp),%rax ; rax에 obj 포인터 값 넣음
  40. // mov (%rax),%rax ; rax에 A struct의 virtual method table 포인터 값 넣음
  41. // add $0x10,%rax ; rax에 vfooC 함수의 포인터를 가르키는 포인터 값 넣음
  42. // mov (%rax),%rax ; rax에 vfooC 함수의 포인터 값 넣음
  43. // mov -0x8(%rbp),%rdx ;
  44. // mov %rdx,%rdi ; rdi에 obj 포인터 값 넣음
  45. // callq *%rax ; virtual call
  46. }
  47.  
  48. int main() {
  49. Obj obj;
  50. test1(obj);
  51. test2(&obj);
  52. return 0;
  53. }



[Enviromnent]
$ uname -a
Linux kali 4.12.0-kali2-amd64 #1 SMP Debian 4.12.12-2kali1 (2017-09-13) x86_64 GNU/Linux
$ g++ --version
g++ (Debian 7.2.0-5) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.




[Download]