I have a theoretical question about C++. It was part of the final exam at my university and I want to know why the method f
of class B
is called, while it should be derived by the base class A
. Since it is not virtual shouldn't the A::f() be called?
#include <iostream.h>
#include <stdlib.h>
class A{
public:int f(int x){
cout<< x << " ";
}
};
class B:public A{
public:int f(int y){
A::f(y+1);
}
};
void g(A a, B b) {
a.f(3);
b.f(3);
}
int main()
{
B p;
B q;
g(p,q);
system("PAUSE");
return 0;
}
// result is 3 4
The static type if b
in g()
is B
, thus there is no need for virtual here - the compiler can know [at compile time] you want to invoke B::f()
, and that is exactly what he is doing.
In here, the class B
redefined A
's f()
, and hides it, so invoking f()
from a variable whose static type is B
results in invoking B::f()
Note that the virtual
keyword allows you to use overriding methods where the static type is the parent's type.
The method g
takes two arguments, of type A
and B
repsectively. Since these are no pointer or reference types, dynamic binding does not apply. The compiler knows at compile time the actual type of the objects, and does a static method call.
virtual
methods only apply if you have pointers or references!
The function int f(int)
in class B
"hides" the function with the same name and signature in its base class.
So, when you call bf(3);
, and the variable b
has type B
, you are calling B::f
.
Virtual functions are only needed if you want bf(3)
to call B::f
in cases where the type of the variable b
is A&
, but the object it refers to has runtime type B
. In that situation, the function called would be B::f
if A::f
is virtual, but A::f
is called if non-virtual.
Virtual function calls take the runtime type of objects into account even if they're used via a pointer or reference to a base class. But B b; bf(3)
B b; bf(3)
is a call to B::f
regardless of whether A::f
even exists, never mind whether it's virtual or non-virtual.
"Non-scientific" explanation:
The function g
treats gets a copy of a
as if it was an instance of A
p
as an object of type A
(see comments below) , and executes the f
from within A
. b
is treated as an instance of B
, where the method Bf
overrides Af
, so when b
is "looked at" as an instance of B
and we execute bf
, the method Bf
will be executed, because the Af
is not visible
If you'd like to call Af
using bf
you'd have to cast b
to A
: ((A)b).f()
.
There are 2 things happening here:
f()
function is not an override because it is not virtual, and really you should not be doing this. You would overcome the slicing by making the function g take its first parameter by reference. If A was given a protected copy-constructor that would also prevent it, although then you would not be able to copy genuine instances of A.
In this case your function g will always call A::f()
even with reference to A because there is no polymorphism. To invoke that you will need to declare A::f()
as virtual.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.