See also [[understanding and using c pointers]], which has about 5 pages (with sample code) on how to implement polymorphism. It covers some non-trivial details of the implementation.
Basic techniques and principles…. Emphasis in this write-up is clarity through simplicity, not rigor or correctness.
_instance_field_ — implemented as field of struct.
** Let’s say the struct type is MyClass.
_instance_method_ — function pointer field in the struct. Each function is an ordinary free functions taking ptr-to-MyClass as 1st parameter. Compiler converts all instance-method calls to function calls with “this” as 1st argument.
_static_method_ — instance methods without that 1st parameter.
_this_ — special hidden read-only field in MyClass of “ptr-to-MyClass” type. Through this pointer, Each instance MyClass knows the address of its own real-estate. As explained in other posts such as Object.java size, such a 32-bit real estate usage in every MyClass instance is rather costly and probably avoided in a c++ compiler. Can we avoid it in our home-made class?
_virtual_methods_ — a bunch of identically named free functions each taking a different type of 1st parameter. Note overload isn’t allowed in C.
— ptr-to-ClassB vs ptr-to-ClassD
_vptr_ — another hidden field in the struct, pointing to an array of function pointers.
_inheritance_ — MyClassD struct encloses/embeds (not a pointer to but) an entire MyClassB struct. Note the instances of MyClassB and MyClassD have the same address, permitting pointer cast.
_private_ — a compile-time access check on members of the struct