Reputation: 359
I have a question in virtual function and reference. It's from a puzzle when I try to prepare interview. I google it for a while but cannot see the exact case.
The code is given as:
class A{
public:
virtual void foo() {cout << "A::foo" << endl;}
};
class B: public A{
public:
void foo() {cout << "B::foo" << endl;}
};
class C: public B{
public:
void foo() {cout << "C::foo" << endl;}
};
int main(void){
C c;
B *q;
q = &c; q->foo();
return 0;
}
My thought to the output will be B::foo, but the answer is actually C::foo. Can someone tell me why the vtable wont choose B's implementation? Thanks
Upvotes: 0
Views: 1373
Reputation: 792059
foo
is virtual in B
because it overrides a virtual function from a base class even though it is not explicitly declared as virtual
.
The most derived type of the object called through q->foo()
is C
and C
's final overrider for foo
with the signature void foo()
is C::foo
so this is the function that is called.
Upvotes: 2
Reputation: 27233
foo()
is a virtual function, which means that the version defined in the class whose instance is actually pointed to by q
is called rather than the one defined in the class in the pointer's type.
Remember that a member function is virtual once it is marked virtual somewhere up the class hierarchy, i.e. one needs not explicitly mark the function as virtual again in classes B and C since this has already been done in class A.
Upvotes: 0
Reputation: 490178
If foo
was not virtual, then the function called would be based on the type of the pointer, and B::foo()
would be called.
Since foo
is defined virtual in the base class, it remains virtual in all derived classes. That being the case, the function that's called is based on the type of object pointed at rather than the type of the pointer. Since the object pointed at is a C
, the function that gets called is C::foo()
.
Upvotes: 2
Reputation: 109159
Can someone tell me why the vtable wont choose B's implementation?
That is the whole point of having virtual functions, so that calling an overriden method through a base class pointer will still call the method from the derived class.
q
is of type B *
, but it is pointing to a C
object. So, when you call the virtual function foo()
the C::foo()
implementation gets called.
Even though foo()
is not marked virtual
in B
and C
, it is still a virtual function because it is declared as such in A
.
If you want B::foo()
to get called you'll need to call it explicitly.
q->B::foo();
Upvotes: 0
Reputation: 3089
Because q
points to a C
object and its virtual function table contains a virtual function foo
. Remember that any virtual function declared in a class is virtual in any derived class. This is the way of using base classes to access to derived ones.
Upvotes: 1
Reputation: 10061
Afaik:
Once vtables are used - which is in this case forced by the virtual
declaration of A::foo
- it's not important what type you declare, it'll always call the method of most specific method - which is in this case C::foo
.
Upvotes: 0