📜 ⬆️ ⬇️

C ++ MythBusters. The myth of virtual functions

Hello.

In the last article, I told you what not everyone knows a particular feature that can be encountered when working with inline functions. The article generated both a few substantive remarks and multi-page disputes (and even holivars), which began with the fact that it is better not to use inline functions at all, and which have turned into a standard C vs. theme. C ++ vs. Java vs. C # vs. vs. PHP vs. Haskell vs. ...

Today it is the turn of virtual functions. And, first, I will at once make a reservation that my article (in principle, like the previous one) in no way pretends to be complete. And secondly, as before, this article is not for professionals. It will be useful to those who are already well versed in the basics of C ++, but have not enough experience, or those who do not like to read books.
')
I hope everyone knows what virtual functions are and how they are used, since it’s not my task to explain. I am sure that RFry, in a cycle of his articles on C ++, will sooner or later reach them.

If in the material about inline-methods the myth was not entirely obvious, in this it is the opposite. Actually, let's move on to the “myth”.

Virtual functions and the virtual keyword

To my surprise, I very often came across and came across people (what can I say, I myself was the same), who believe that the virtual keyword makes the function virtual only at one level of hierarchy . Let me explain what I mean by example:

#include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  1. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  2. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  3. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  4. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  5. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  6. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  7. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  8. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  9. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  10. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  11. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  12. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  13. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  14. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  15. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  16. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  17. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  18. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  19. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  20. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  21. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  22. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  23. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  24. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  25. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  26. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  27. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  28. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  29. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  30. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  31. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  32. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  33. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  34. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  35. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  36. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  37. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
#include <cstdlib> #include <iostream> using std::cout; using std::endl; struct A { virtual ~A() {} virtual void foo() const { cout << "A::foo()" << endl; } virtual void bar() const { cout << "A::bar()" << endl; } void baz() const { cout << "A::baz()" << endl; } }; struct B : public A { virtual void foo() const { cout << "B::foo()" << endl; } void bar() const { cout << "B::bar()" << endl; } void baz() const { cout << "B::baz()" << endl; } }; struct C : public B { virtual void foo() const { cout << "C::foo()" << endl; } virtual void bar() const { cout << "C::bar()" << endl; } void baz() const { cout << "C::baz()" << endl; } }; int main() { cout << "pA is B:" << endl; A * pA = new B; pA->foo(); pA->bar(); pA->baz(); delete pA; cout << "\npA is C:" << endl; pA = new C; pA->foo(); pA->bar(); pA->baz(); delete pA; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .

So, we have a simple class hierarchy. In each class 3 methods are defined: foo () , bar () and baz () . Consider the wrong logic of people who are under the influence of myth :
when the pointer pA points to an object of type B, we have the output:
pA is B:
B :: foo () // because in the parent class A the foo () method is marked as virtual
B :: bar () // because in the parent class A the bar () method is marked as virtual
A :: baz () // because in the parent class A the baz () method is not marked as virtual

when the pointer pA points to an object of type C, we have the conclusion:
pA is C:
C :: foo () // because in the parent class B the foo () method is marked as virtual
B :: bar () // because in the parent class B the bar () method is not marked as virtual,
// but it is marked as virtual in class A, the pointer to which we use
A :: baz () // because in class A the baz () method is not marked as virtual


With the non-virtual function baz (), everything is clear. But with the logic of calling virtual functions there is a discrepancy. I think it is not necessary to say that in fact the conclusion will be as follows:

pA is B:
B :: foo ()
B :: bar ()
A :: baz ()

pA is C:
C :: foo ()
C :: bar ()
A :: baz ()


Conclusion: the virtual function becomes virtual until the end of the hierarchy, and the virtual keyword is “key” only for the first time, and in subsequent times it carries a purely informative function for the convenience of programmers .

To understand why this is happening, you need to figure out exactly how the mechanism of virtual functions works.

Early and late binding. Virtual function table

Binding is the mapping of a function call to a call. In C ++, all functions by default have early binding , that is, the compiler and linker decide which function should be called before running the program. Virtual functions have late binding , that is, when a function is called, the desired body is selected at the program execution stage.

Having met the virtual keyword, the compiler marks that late binding should be used for this method: first, it creates a table of virtual functions for the class, and adds a new member to the class - a pointer to this table. (In fact, as far as I know, the language standard does not prescribe how exactly the mechanism of virtual functions should be implemented, but the implementation based on the virtual table has become the de facto standard.). Consider this proof:

#include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  1. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  2. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  3. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  4. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  5. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  6. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  7. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  8. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  9. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  10. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  11. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  12. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  13. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  14. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  15. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  16. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  17. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  18. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  19. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  20. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  21. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  22. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  23. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  24. #include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
#include <cstdlib> #include <iostream> struct Empty {}; struct EmptyVirt { virtual ~EmptyVirt(){} }; struct NotEmpty { int m_i; }; struct NotEmptyVirt { virtual ~NotEmptyVirt() {} int m_i; }; struct NotEmptyNonVirt { void foo() const {} int m_i; }; int main() { std::cout << sizeof (Empty) << std::endl; std::cout << sizeof (EmptyVirt) << std::endl; std::cout << sizeof (NotEmpty) << std::endl; std::cout << sizeof (NotEmptyVirt) << std::endl; std::cout << sizeof (NotEmptyNonVirt) << std::endl; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .

The output may differ depending on the platform, but in my case (Win32, msvc2008) it was as follows:

one
four
four
eight
four


What can be understood from this example. First, the size of the “empty” class is always greater than zero, because the compiler specifically inserts a dummy term into it. As Ekkel writes, “imagine the indexing process in an array of objects of zero size, and everything will become clear”;) Secondly, we see that the size of the “non-empty” class NotEmptyVirt when adding a virtual function to it increased by the standard size of the pointer to void; and in the empty class EmptyVirt, the dummy member that the compiler had previously added to reduce the class to a non-zero size was replaced with a pointer. At the same time, adding a non-virtual function to a class does not affect the size (thanks to nullbie for the advice ). The name of the pointer to the table differs depending on the compiler. For example, the Visual Studio 2008 compiler calls it __vfptr, and the table itself 'vftable' (who does not believe, can look in the debugger :) In the literature, the pointer to the table of virtual functions is called VPTR, and the table VTABLE, so I will stick to the same notation.

What is a virtual function table and what is it for? The virtual function table stores the addresses of all the virtual methods of a class (in fact, it is an array of pointers), as well as all the virtual methods of the base classes of this class.

There will be as many virtual function tables as there are classes containing virtual functions — one table per class. The objects of each class contain exactly the pointer to the table, and not the table itself! Questions on this topic like to ask the teachers, as well as those who conduct interviews. (Examples of tricky questions on which you can catch newbies: “if a class contains a table of virtual functions, then the size of the class object will depend on the number of virtual functions contained in it, right?”; “We have an array of pointers to the base class, each of which indicates on the object of one of the derived classes - how many virtual functions tables will we have? ”, etc.).

So, for each class we will create a table of virtual functions. Each virtual function of the base class is assigned a successive index (in the order of the function declaration), which will determine the address of the function body in the VTABLE table. When inheriting a base class, the derived class "receives" and a table of addresses of the virtual functions of the base class. If any virtual method in a derived class is overwritten, then in the virtual functions table of this class, the body address of the corresponding method will simply be replaced with a new one. When new derived VTABLE virtual methods are added to the derived class, the derived class expands, and the base class table naturally remains the same as it was. Therefore, through a pointer to the base class, you cannot virtually call the methods of the derived class that were not in the base class, because the base class “does not know anything about them” (then we will all look at an example).

The class constructor should now do an additional operation: initialize the VPTR pointer with the address of the corresponding virtual function table. That is, when we create a derived class object, the base class constructor is first called, initializing the VPTR with the address of its “virtual function table”, then the derived class constructor is called, which rewrites this value.

When calling a function through the base class address (read through the pointer to the base class), the compiler must first refer to the virtual functions table of the class using the VPTR pointer, and get the body address of the function being called from it, and only after that do the call.

From the foregoing, it can be concluded that the late binding mechanism requires additional CPU time (initialization of the VPTR by the designer, obtaining the address of the function when it is called) compared to the early one.

I think the example will become clearer. Consider the following hierarchy:



In this case, we get two tables of virtual functions:
Base
0
Base :: foo ()
oneBase :: bar ()
2Base :: baz ()

and
Inherited
0
Base :: foo ()
oneInherited :: bar ()
2Base :: baz ()
3Inherited :: qux ()


As you can see, in the table of the derived class, the address of the second method has been replaced with the corresponding overridden. Proof Code:

#include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  1. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  2. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  3. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  4. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  5. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  6. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  7. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  8. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  9. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  10. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  11. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  12. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  13. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  14. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  15. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  16. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  17. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  18. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  19. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  20. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  21. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  22. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  23. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  24. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  25. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  26. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  27. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  28. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
  29. #include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .
#include <cstdlib> #include <iostream> using std::cout; using std::endl; struct Base { Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } virtual void foo() { cout << "Base::foo()" << endl; } virtual void bar() { cout << "Base::bar()" << endl; } virtual void baz() { cout << "Base::baz()" << endl; } }; struct Inherited : public Base { Inherited() { cout << "Inherited::Inherited()" << endl; } virtual ~Inherited() { cout << "Inherited::~Inherited()" << endl; } virtual void bar() { cout << "Inherited::bar()" << endl; } virtual void qux() { cout << "Inherited::qux()" << endl; } }; int main() { Base * pBase = new Inherited; pBase->foo(); pBase->bar(); pBase->baz(); //pBase->qux(); // delete pBase; return EXIT_SUCCESS; } * This source code was highlighted with Source Code Highlighter .

What happens when the program starts? First, we declare a pointer to an object of type Base, to which we assign the address of a newly created object of type Inherited. This calls the Base constructor, initializes the VPTR with the VTABLE address of the Base class, and then the Inherited constructor, which overwrites the VPTR value with the VTABLE address of the Inherited class. When pBase-> foo () , pBase-> bar () and pBase-> baz () are called, the compiler uses the VPTR pointer to retrieve the actual address of the function body from the virtual function table. How does this happen? Regardless of the specific type of object, the compiler knows that the address of the foo () function is in the first place, bar () is in the second, and so on. (as I said, in the function declaration). Thus, to call, for example, the baz () function, it receives the address of the function as VPTR + 2 - the offset from the beginning of the virtual function table, stores this address and inserts it into the call command. For the same reason, calling pBase-> qux () leads to an error: despite the fact that the actual type of the Inherited object, when we assign its address to the pointer to Base, there is an upward type conversion, and there is no fourth method in the VTABLE table of the Base class therefore, VPTR + 3 would indicate “foreign” memory (fortunately, such code is not even compiled).

Let's go back to the myth. It becomes obvious that with this approach to the implementation of virtual functions it is impossible to make the function virtual only for one level of the hierarchy.

It also becomes clear why virtual functions work only when accessing an object’s address (via pointers or via links). As I said, in this line
Base * pBase = new Inherited;
an up-conversion occurs: Inherited * is cast to Base *, but in any case, the pointer merely stores the address of the object "start" in memory. If, on the other hand, an up-bringing is done directly for an object, then it is actually “trimmed” to the size of the base class object. Therefore, it is logical that the early binding is used to call functions “through the object” - the compiler and so “knows” the actual type of the object.

Actually, that's all. Waiting for comments. Thanks for attention.

PS This article is labeled "Warranty of Fare" ©
(Skor, if you read this, this is for you;)

PPS Yes, I forgot to say ... Javista will now start shouting that in Java, by default, all functions are virtual.
_________
The text was prepared in Habra Editor

Progg it

Source: https://habr.com/ru/post/51229/


All Articles