#include <iostream>
using namespace std;
class Base1 {
public:
virtual void foo() { cout << "Base1::foo\n"; }
int b1_data = 1;
};
class Base2 {
public:
virtual void bar() { cout << "Base2::bar\n"; }
int b2_data = 2;
};
class Derived : public Base1, public Base2 {
public:
int derivedData = 999;
void foo() override { cout << "Derived::foo, derivedData=" << derivedData << "\n"; }
void bar() override { cout << "Derived::bar, derivedData=" << derivedData << "\n"; }
};
Derived* d = new Derived();
Base1* b1 = d;
Base2* b2 = d;
b1->foo(); // Calls Derived::foo()
b2->bar(); // Calls Derived::bar()
Is b2->bar() safe?
It accesses derivedData in Derived. The actual C function is like Derived::bar(this).
Whose this pointer is passed to this function?
Is it the address of the Base2 component?
It's fine.
The actual function that appears in the Base2 subobject v-table is a trampoline. Something like
void Derived__Base2_bar(Base2* _Base2_this)
{
Derived* _Derived_this = static_cast<Derived*>(_Base2_this); // intptr_t(_Base2_this) - offsetofbase(Derived, Base2)
return Derived__bar(_Derived_this);
}
If you had virtual inheritance, it would get complicated. But this is not.
You could also get a compiler-generated trampoline like this when using return type covariance, and then the "return" downcast would also be computing an offset.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With