I have been coding up a reference thing for virtual functions since I always forget some piece of how they work. Here is what I have thus far:
#include <iostream>
using namespace std;
struct Base
{
virtual void foo(int one = 1, int two = 2) = 0;
virtual Base* bar() { cout << "Base bar\n"; return this; }
virtual void baz(Base*) { cout << "Base baz\n"; }
virtual void boo(Base*) { cout << "Base boo\n"; }
// Error: templates may not be virtual
//template <typename T> virtual T bad(T t) {return t}
virtual ~Base() {}
};
struct Derived : public Base
{
void foo(int one = 3, int two = 4)
{ cout << "one: " << one << " two: " << two << endl; }
Derived* bar() { cout << "Derived bar\n"; return this; }
void baz(Derived*) { cout << "Derived baz\n"; }
using Base::boo;
void boo(Derived*) { cout << "Derived boo\n"; }
};
void example1()
{
Base* pB = new Derived();
Derived* pD = new Derived();
// Foo is called with default parameters based on pointer
pB->foo(); // one: 1 two: 2
pD->foo(); // one: 3 two: 4
// Bar is overridden because return type can be implicitly converted
pB->bar(); // Derived bar
pD->bar(); // Derived bar
// Baz is not overridden because parameters differ
pB->baz(pB); // Base baz
pB->baz(pD); // Base baz
//pD->baz(pB); // invalid conversion from Base* to Derived*
pD->baz(pD); // Derived baz
// Boo using test
pB->boo(pB); // Base boo
pB->boo(pD); // Base boo
pD->boo(pB); // Base boo
pD->boo(pD); // Derived boo
delete pB;
delete pD;
}
struct Base2
{
void foo(int one = 1, int two = 2) { foo_impl(one, two); }
virtual ~Base2() {}
private:
virtual void foo_impl(int one, int two) = 0;
};
struct Derived2 : public Base2
{
private:
void foo_impl(int one, int two)
{ cout << "one: " << one << " two: " << two << endl; }
};
void example2()
{
Base2* pB = new Derived2();
Derived2* pD = new Derived2();
// Now one set of default parameters exists
pB->foo(); // one: 1 two: 2
pD->foo(); // one: 1 two: 2
delete pB;
delete pD;
}
int main()
{
example1();
example2();
return 0;
}
I am confused by the boo() function. It seems to me that pB->boo(pD)
near the end of example1()
should call the overridden version of the function, but it calls the base version. Why? If you could explain where all using
is needed and how it works, that would be helpful, thanks.
Also, if you can think of other pitfalls to watch for when using virtual functions, feel free to post those too. Thanks.
The answer can be see by what happens with the baz
function. As you note in your comment, the derived class's baz
does not override the base class's version because the parameters differ. That's the same case for boo
.
Your using Base::boo;
statement doesn't in any way change boo
not overriding. Instead it just brings the base version in scope for the derived class. Essentially, it's as if the derived class then has two overloads of the function.
However with pB->boo(pD);
overloads aren't relevant since the pointer is typed in terms of Base
. So the compiler only knows about the base class's boo
function. And thus since nothing is overriding boo
it ends up calling the base version.