consider the following program:
class Base {
public:
virtual void foo() const {
cout << "Base::foo()" << endl;
}
};
class Derived : public Base {
public:
virtual void foo() {
cout << "Der开发者_如何学Goived::foo()" << endl;
}
};
void func(Base& obj) {
obj.foo();
}
void main() {
Derived d;
func(d); // Base::foo() is printed
}
If I remove the const
from the Base
class foo
method then Derived::foo()
is called.
I can't seem to understand this behavior.
1) What is the reason for this behavior?
2) Is this decided at compile time or runtime?
Thanks
In the derived class, the function signature is this:
virtual void foo(); //Derived::foo
which doesn't mention const
. Its a non-const member function, while the Base::foo
is a const member function. They're two different functions, because const
is a part of the function signature.
virtual void foo() const; //Base::foo
Derived class does NOT override this function, instead it adds another function.
So the fix is this:
class Derived : public Base {
public:
virtual void foo() const {
cout << "Derived::foo()" << endl;
}
};
As const
is a part of the function signature. So you must mention it when you intend to override base's foo.
@davka's asked:
so why the const version is selected over the non-const? Is there any rule or it just happened to be the first option?
Its because the static type of obj
is Base
, and function name is resolved based on the static type of object. Base
doesn't even have non-const version. So there is no question of it being selected or rejected. It doesn't exist in Base
to begin with.
void func(Base& obj) {
obj.foo(); //calls Base::foo
}
However, if you change the above code to the following:
void func(Derived & obj) {
obj.foo(); //calls Derived:foo
}
Now non-const version will be selected, because Base::foo
is hidden in Derived
class.
Since Derived::foo
hides the Base::foo
, so you cannot call the latter using an instance of Derived
.
Now, lets unhide Base::foo
and do some more experiments.
class Derived : public Base {
public:
using Base::foo; //<----------------this unhides Base::foo
virtual void foo() {
cout << "Derived::foo()" << endl;
}
};
Now in Derived, both functions (const as well as non-const version) are available, unhidden. Now few interesting questions.
Since now Derived has both functions unhidden, which function will be called in each function below?
void f(Derived& obj) {
obj.foo(); //Which function? Base::foo or Derived::foo?
}
void g(const Derived & obj) {
obj.foo(); //Which function? Base::foo or Derived::foo?
}
First one will call Derived::foo
which is non-const version, and second one will call Base::foo
which is const version. The reason is simple, with const object, only const functions can be invoked, but with non-const objects, both can be invoked, however non-const version is selected if its available.
See online demo : http://www.ideone.com/955aY
You aren't overriding the method, since Derived::foo
isn't exactly the same.
To override a method, the base and overridden versions must be identical, including const
-ness.
In C++, you can have two functions with the same name and the same parameters, where the only difference that one is const
and one is not.
The idea is that you sometimes want different behaviors. For example, an access function function might have different return types:
class MyClass
{
public:
virtual Xxx * GetXxx();
virtual Xxx const * GetXxx() const;
// ....
}
You can override these functions individually.
In your case, as you call foo
from a non-const object, you called the non-const variant of the function. As you had overridden the const-variant, the one in the base class is the one being called.
What you're doing is called "overloading." In overriding, as @SLaks pointed out, the signature needs to be the same.
const
is part of the signature. void foo() const
is a different function from void foo()
. You are not overriding at all. That's why.
精彩评论