Consider the next code :
#include <iostream>
using namespace std;
class A
{
public:
virtual int f() {cout <<"A:: f()\n"; return 1;}
virtual void f(int) {cout <<"A:: f(int)\n";}
virtual void g() {cout <<"A::g()\n";}
};
class B3 : public A
{
public:
void f() {cout <<"B3::f ()\n";}
};
int main()
{
return 0;
}
It produces the following error :
..\main.cpp:17: error: conflicting return type specified for 'virtual void B3::f()'
..\main.cpp:9: error: overriding 'virtual int A::f()'
but why ? in the worst case I'd think I'd have an Hiding case , but instead I get compilation error regarding A's virtual int f() {cout <<"A:: f()\n"; return 1;}
thanks ,Ronen
Don't confuse overriding with hiding. You override virtuals.
Your class definition is equivalent to:
class B3 : public A
{
public:
virtual void f() {cout <<"B3::f ()\n";}
};
Once a function declared virtual, it will remain virtual for all classes deriving from your base class, regardless of whether you explicitly declare it virtual or not. Therefore you are trying to override a virtual function and changing its return type, which is illegal in C++. If the function were not virtual, you would simply be hiding the base class implementation, therefore changing the return type is valid. There would be no ambiguity since the compiler would know where to call the function from and what return type to expect.
However, consider having:
A* a;
....
a->f();
What would a-f() return? a is a pointer to A, but can point to an object of type B3. So it either returns an int or doesn't return anything. See the ambiguity here?
Instead, no polymorphism involved,
A a;
a.f();
will cal f from a, same as b3.f would call f from B3.
All in all, overriding base class functions implies keeping the same return type. If you want to create a new function with a different return type, change its signature (either its name or its parameters - or both).
Anyway, you shouldn't even be doing this... Why would you want to have a function with the same name and no parameters return different things? Wouldn't adding a separate function be more readable?
You'd have hiding if f() would have had a different parameter list, or not declared as virtual on the base class. In the former case, since overloading doesn't cross inheritance borders, A's f would have been hidden. But this is not the case, since you have f() on both classes, which only differ in return value. Return values covariance is the only difference allowed, and since it's not the case (void does not inherit from int), you get the error.
Related
Base class:
class Base
{
public:
virtual int f() const
{
return 1;
}
};
Derived class:
class Derived: public Base
{
public:
void f() const {}
};
Above code throws a "return type is not identical/covariant error".
I've read few discussions on it. This one is similar but they only say that it will break the code if the return types aren't identical/covariants.
Override a member function with different return type
Why the behavior I'm expecting doesn't happen?
Expected Behavior: The VPTR in Derived points to Base::f() (I've read incase an override isn't provided for a virtual function, Derived objects will just uses the inherited class version ). Also it hides the name f() so now a call like this:
Derived x;
x.f();
should've called Derived::f() and a call like this:
x.Base::f();
should've called the Base::f() function. This doesn't seem like breaking the code.
Incase its upcasted, even then it shouldn't break the code because VPTR for both classes points to the same Base::f()
The only reason I can think of is that such a declaration(same signature and covariant/identical return types) is reserved for overriding virtual methods and we just cannot use it to cause the behavior I'm expecting.
When the compiler encounters the matching signature (arguments, constness), it automatically makes the void f() const declaration virtual. So the definition of Derived is interpreted as:
class Derived: public Base
{
public:
virtual void f() const {} // virtual keyword is added
};
It clearly looks like an attempt to override Base::f(). All this happens because the function signatures match in the Base and Derived class. If the signatures didn't match, then only would this be a redefinition in which case it would've hidden the Base::f() in Derived class.
Suppose we have the following code:
class Base
{
public:
virtual void foo() const
{ cout << "In Base::foo\n"; }
}
class Derived : public Base
{public:
virtual void foo()
{ cout << "In Derived::foo\n"; }
}
void main()
{
Base* b = new Derived();
b->foo();
delete b;
}
It will give us the following output: In Base::foo.
Now suppose I want to get - without changing the main function - the follwing output instead the one given above:
In Derived::foo
As far as I understand, I should override the function foo() of in the base, to get the output of the method
foo() in the inheriting class which is class 'Derived'.
But the problem is that in that case I can't using the command override, becuase the method in the base is defined as constant , which in the other class it is not.
So, how should I if then overriding that method ?
In order to override the function void foo() const of the base class, you must declare the function void foo() const in the derived class. You've declared the function void foo() instead (note the lack of const), which doesn't override the function in the base, because it has a different declaration.
So, how should I if then overriding that method ?
Add the missing const qualifier.
P.S. Few other bugs in your program:
main must return int.
Class definitions must end in a semicolon.
Deleting a derived object through a pointer to base has undefined behaviour unless the destructor of the base is virtual.
Consider the following class definitions:
class foo {
virtual absl::Span<const Input *const> GetInputs() const = 0;
virtual absl::Span<Input *const> GetInputs() {
auto mutable_inputs = GetMutableInputs();
return absl::MakeSpan(mutable_inputs.begin(), mutable_inputs.end());
}
}
class bar : public foo {
absl::Span<const Input *const> GetInputs() const override {
return absl::MakeConstSpan(inputs_);
}
}
When calling bar.GetInputs() it seems like the only implementation found is the the one that returns a span of constant inputs. If I have an instance of bar, and want to create a span of non-const inputs, then I must cast bar to foo, and then call GetInputs.
If I cast bar to foo, then call GetInputs, I am then able to assign the result to a span of non-const inputs. Why does the compiler fail to identify the inherited non-const method with the correct return type? Is there a way to make the subclass identify that method?
In other words, is there a way to make the following code compile:
absl::Span<Input *const> tmp = bar.GetInputs()
If I understand your question, it has nothing to do with virtual functions or "precedence" of const, but is plain old "name hiding".
#include <iostream>
class Base {
public:
virtual void f(int) { std::cout << "Base(int)\n"; }
virtual void f(double) { std::cout << "Base(double)\n"; }
};
class Derived : public Base {
public:
virtual void f(double) { std::cout << "Derived(double)\n"; }
};
int main() {
Derived d;
int x=0;
d.f(x);
}
output: Derived(double)
The issue is, name lookup doesn't work the way it seems you expect.
For a given scope, it searches for names to build an overload set. Within the context of Derived, there is only one f(), so when it's found, the compiler stops searching further for more overloads.
It finds Derived(double) and that's the entire overload set, and so it is selected. When you cast your derived class to a reference to the base, and then call something, both functions (declared in the base) are considered, and overload resolution selects the best match.
Now, normally, for polymorphic types you are working with the objects in terms of pointers/references to the base, so it's not an issue. But if you are calling directly on the derived class (perhaps from inside a member of derived?) then it'll have this issue of the derived declaration hiding the base names.
To make the base names visible in the derived class, it's easy:
class Derived : public Base {
public:
using base::f; // <<<<<<<< just add this
virtual void f(double) { std::cout << "Derived(double)\n"; }
};
you should add
using foo::GetInputs;
in bar class to expose the base class function.
you will be able to call the base class function if the object is non-const
Lets say I have a class A, B and C
class A{
public:
virtual void f4(){
cerr<<"A::f4()"<<endl;
}
};
class B: public A{
public:
virtual void f4(int n){
cerr<<"B::f4("<<n<<")"<<endl;
}
};
class C: public B{
public:
virtual void f4(int n = 1){
cerr<<"C::f4("<<n<<")"<<endl;
}
};
If I have:
C c;
A& rac = c;
rac.f4();
I was expecting c's version of f4 to be called but that's not what happens. Can someone explain?
Compiling with clang -Wall the following warnings occur:
main.cpp:14:22: warning: 'B::f4' hides overloaded virtual function [-Woverloaded-virtual]
virtual void f4(int n){
^
main.cpp:6:22: note: hidden overloaded virtual function 'A::f4' declared here: different number of parameters (0 vs 1)
virtual void f4(){
^
These warnings explain what's going on. A virtual function is only overridden by another function with the same signature.
B::f4(int) does not override A::f4() because they have different parameter lists. Instead, it is a different virtual function.
So rac.f4() just calls A::f4() which is not overridden.
Since C++11 you can help to detect this problem:
virtual void f4(int n) override {
// ^^^^^^^^
Then the compiler will give an error if this function does not actually override something from the base.
Because the signatures of f4 don't match between A and B/C classes.
This is A's function signature for f4:
void A::f4() // no parameters
B and C use this function signature
void B::f4(int n)
If you are doing to override a method, it needs to have the same return type and identical parameter list. Otherwise, even if the method in the derived class has the same name as the parent class, C++ will don't consider that an override.
FWIW, C::f4 does override B::f4. The default parameter you introduce on class C doesn't influence the virtual methods override behavior. And this is the exact reason why, on my team, we disallow overloading methods with different signatures and banning default parameters. Because it leads to bugs like this.
Here's C's v-table (the methods available on it):
void C::f4(); // no parameters, overrides A::f4()
void C::f4(int n); // overrides B::f4()
I would expect that if foo is declared in class D, but not marked virtual, then the following code would call the implementation of foo in D (regardless of the dynamic type of d).
D& d = ...;
d.foo();
However, in the following program, that is not the case. Can anyone explain this? Is a method automatically virtual if it overrides a virtual function?
#include <iostream>
using namespace std;
class C {
public:
virtual void foo() { cout << "C" << endl; }
};
class D : public C {
public:
void foo() { cout << "D" << endl; }
};
class E : public D {
public:
void foo() { cout << "E" << endl; }
};
int main(int argc, char **argv)
{
E& e = *new E;
D& d = *static_cast<D*>(&e);
d.foo();
return 0;
}
The output of the above program is:
E
Standard 10.3.2 (class.virtual) says:
If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name and same parameter list as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides*
[Footnote: A function with the same name but a different parameter list (clause over) as a virtual function is not necessarily virtual and does not override. The use of the virtual specifier in the declaration of an overriding function is legal but redundant (has empty semantics). Access control (clause class.access) is not considered in determining overriding. --- end foonote]
Quick answer may be no, but correct answer is yes
C++ doesn't know about function hiding, so overriding virtual function without virtual keyword marks that function virtual too.
You are not creating any copy of the object of e and putting it in d. So d.foo() follows normal polymorphic behavior and calls derived class method. A method which is declared as virtual in the base class becomes automatically virtual in the derived class also.
The output ("E") behaves exactly as one would expect it to behave.
The reason:
The dynamic (i.e. runtime) type of that reference is E. You are doing a static upcast to D, but that does not change the actual type of the object of course.
That's the very idea behind virtual methods and dynamic dispatches: You see the behavior of the type you were instantiating, which is E, in this case.