diff --git a/README.adoc b/README.adoc index d212f8b..fed840e 100644 --- a/README.adoc +++ b/README.adoc @@ -17265,6 +17265,8 @@ Programs under link:userland/cpp/[] are examples of https://en.wikipedia.org/wik *** link:userland/cpp/most_vexing_parse.cpp[]: the most vexing parse is a famous constructor vs function declaration syntax gotcha! **** https://en.wikipedia.org/wiki/Most_vexing_parse **** http://stackoverflow.com/questions/180172/default-constructor-with-empty-brackets +** `virtual` and polymorphism +*** link:userland/cpp/virtual.cpp[] * templates ** link:userland/cpp/template.cpp[]: basic example ** link:userland/cpp/template_class_with_static_member.cpp[]: https://stackoverflow.com/questions/3229883/static-member-initialization-in-a-class-template @@ -19019,7 +19021,7 @@ Examples: * link:userland/linux/sched_getcpu.c[] * link:userland/linux/getcpu.c[]: a wrapper close the the syscall that also returns the current NUMA node -* link:userland/linux/getcpu_syscal.c[]: the wrapper segfaults on error handling, so double checking with the real syscall: https://stackoverflow.com/questions/9260937/unix-socket-error-14-efault-bad-address/61879849#61879849 +* link:userland/linux/getcpu_syscall.c[]: the wrapper segfaults on error handling, so double checking with the real syscall: https://stackoverflow.com/questions/9260937/unix-socket-error-14-efault-bad-address/61879849#61879849 * link:userland/linux/sched_getcpu_barrier.c[]: this uses a barrier to ensure that gem5 will run each thread on one separate CPU Returns the CPU that the process/thread is currently running on: diff --git a/userland/cpp/virtual.cpp b/userland/cpp/virtual.cpp new file mode 100644 index 0000000..d09855a --- /dev/null +++ b/userland/cpp/virtual.cpp @@ -0,0 +1,116 @@ +// https://cirosantilli.com/linux-kernel-module-cheat#cpp + +#include + +int main() { + + // Hello world. + { + struct Base { + virtual int f() { return 0; } + }; + + struct Derived1 : public Base { + virtual int f() override { return 1; } + }; + + struct Derived2 : public Base { + // virtual not required on the last derived method. + int f() override { return 2; } + }; + + // Depending on what bp actually points to, we call different functions. + // This is what is called polymorphism. + + Base *bp; + + Base b; + bp = &b; + assert(bp->f() == 0); + + Derived1 d1; + bp = &d1; + assert(bp->f() == 1); + + Derived2 d2; + bp = &d2; + assert(bp->f() == 2); + } + + // Without `virtual`, no polymorphism happens! + // We get name hiding instead. + { + struct Base { + int f() { return 0; } + }; + + struct Derived : public Base { + int f() { return 1; } + }; + + Base *bp; + + Base b; + bp = &b; + assert(bp->f() == 0); + + Derived d; + bp = &d; + // Base method called! + assert(bp->f() == 0); + } + + // If the derived signature is not compatible with the virtual, + // no polymorphism happens! + // + // Also see "covariant return" for compatibility of return types. + // + // This is why you should always use override to prevent such bugs. + { + struct Base { + virtual int f() { return 0; } + }; + + class Derived : public Base { + virtual int f(int i) /* override */ { return i; } + }; + + Base *bp; + + Base b; + bp = &b; + assert(bp->f() == 0); + + Derived d; + bp = &d; + // Base method called! + assert(bp->f() == 0); + + // ERROR: no matching function. +#if 0 + assert(bp->f(1) == 1); +#endif + } + + // Polymorphic calls cannot be made from constructors. + // https://stackoverflow.com/questions/1453131/how-can-i-get-polymorphic-behavior-in-a-c-constructor + { + struct Base { + int i; + Base() { + i = f(); + } + virtual int f() { return 0; } + }; + + class Derived : public Base { + int f() override { return i; } + }; + + Base b; + assert(b.i == 0); + + Derived d; + assert(d.i == 0); + } +}