I just thought of a way to tell at runtime, without guesswork. You can simply override the vptr of your polymorphic classes with 0 and see if the method is called or if you get a segmentation fault. This is what I get for my example:
Concrete: Base
Concrete: Derived
Pointer: Base
Pointer: Derived
DELETING VPTR!
Concrete: Base
Concrete: Derived
Segmentation fault
Where Concrete: T
means that calling the virtual member function of T
through a concrete type was successful. Analogously, Pointer: T
says that calling the member function of T
through a Base
pointer was successful.
For reference, this is my test program:
#include <iostream>
#include <string.h>
struct Base {
unsigned x;
Base() : x(0xEFBEADDEu) {
}
virtual void foo() const {
std::cout << "Base" << std::endl;
}
};
struct Derived : Base {
unsigned y;
Derived() : Base(), y(0xEFCDAB89u) {
}
void foo() const {
std::cout << "Derived" << std::endl;
}
};
template <typename T>
void dump(T* p) {
for (unsigned i = 0; i < sizeof(T); i++) {
std::cout << std::hex << (unsigned)(reinterpret_cast<unsigned char*>(p)[i]);
}
std::cout << std::endl;
}
void callfoo(Base* b) {
b->foo();
}
int main() {
Base b;
Derived d;
dump(&b);
dump(&d);
std::cout << "Concrete: ";
b.foo();
std::cout << "Concrete: ";
d.foo();
std::cout << "Pointer: ";
callfoo(&b);
std::cout << "Pointer: ";
callfoo(&d);
std::cout << "DELETING VPTR!" << std::endl;
memset(&b,0,6);
memset(&d,0,6);
std::cout << "Concrete: ";
b.foo();
std::cout << "Concrete: ";
d.foo();
std::cout << "Pointer: ";
callfoo(&b);
std::cout << "Pointer: ";
callfoo(&d);
return 0;
}