class Base { public: void foo() { cout << "β\n"; } }; class Derived : public Base { public: void foo() { cout << "Δ\n"; } }; int main() { Derived d; Base *b = &d; b->foo(); return 0; }
β
b->foo()
called the .foo()
method of Base
. Why?
Because b
is a Base *
.
class Base { public: void foo() { cout << "β\n"; } }; class Derived : public Base { public: void foo() { cout << "Δ\n"; } }; int main() { Derived d; Base &b = d; b.foo(); return 0; }
β
Same result with a reference. References are just a variety of pointers, so that’s expected.
These results are unsurprising. If your pointer is a Generic *
,
then p->method()
calls a method of Generic
.
But what if that’s not what you want? What if you have a pointer of
type Generic *
, but it’s really pointing to an object of type
Specific
? It can do that, if Specific
is a subclass (derived
class) of Generic
. You might want p->method()
to call the
method of the object’s actual type, as opposed to its apparent
type.
class Base { public: virtual void foo() { cout << "β\n"; } }; class Derived : public Base { public: virtual void foo() { cout << "Δ\n"; } }; int main() { Derived d; Base *b = &d; b->foo(); return 0; }
Δ
That’s different!
class Base { public: virtual void foo() { cout << "β\n"; } }; class Derived : public Base { public: virtual void foo() { cout << "Δ\n"; } }; int main() { Derived d; Base &b = d; b.foo(); return 0; }
Δ
That’s different!
People often call these “virtual functions”, though a good O-O programmer might call them “virtual methods”. A method is a function, after all.
Not using virtual methods:
Using virtual methods:
There is, of course, a cost to all of this.
class Base { public: virtual void foo() { cout << "β\n"; } }; class Derived : public Base { public: virtual void foo() { cout << "Δ\n"; } string s; // Look--a data member! }; int main() { Base *b = new Derived; b->foo(); delete b; return 0; }
c.cc:15: warning: deleting object of polymorphic class type 'Base' which has non-virtual destructor might cause undefined behavior Δ
If a method is declared virtual
in the base class, it’s
automatically virtual
in all derived classes. It’s virtual
all the way down.
However, I generally repeat the virtual
declaration in each
subclass to remind the reader.