Why can't I override inherited function? - c++

When I tried to compile next construction I have got the error: cannot convert parameter 1 from 'std::vector<_Ty>' to 'float'
Why dose it happen?
class A
{
public:
virtual int action(float)
{return 5;}
virtual int action(std::vector<float>)
{return 10;}
};
class B : public A
{
public:
int action(float) override
{return 6;}
};
class C : public B
{
public:
int action(std::vector<float>) override
{
B::action(std::vector<float>());
return 7;
}
};
int main()
{
C instance;
int temp = instance.action(std::vector<float>());
getchar();
return 0;
}

When the compiler sees a function call
B::action(std::vector<float>());
It needs two steps to decide which function call needs to be made. In the first step it looks up the name action. If the lookup results in one or more functions, it stops the lookup. It does not lookup the overloaded functions in base classes. If the lookup results in multiple function names, it tries overload resolution.
In your case, the lookup results in only one function - int B::action(float). The lookup stops there. However, that function does not match the argument being used. Hence, the compiler reports it as an error.
I can think of the following ways to resolve the problem.
Make all overloads of A::action available for lookup in B
class B : public A
{
public:
using A::action;
int action(float) override
{return 6;}
};
Change the call so it uses A::action(float)
class C : public B
{
public:
int action(std::vector<float>) override
{
A::action(std::vector<float>());
return 7;
}
};
I strongly recommend using the first approach.

The compiler does not search for overloads in parent classes if the derived class declares a function by the same name. Typically, if you've enabled warnings, the compiler would warn something like:
warning: 'C::action' hides overloaded virtual function [-Woverloaded-virtual]
If you specify the scope where the overload is declared, the call will work:
A::action(std::vector<float>());
But more generally, you should always avoid overloading virtual functions.

Related

Is it possible to force non-const virtual methods from superclasses to take precedence over const methods of the same name in a subclass?

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

Inheritance with two functions with different signatures hides the non-virtual function

Forgive the obscure title. It's likely a duplicate but I couldn't find the correct phrase.
Consider the following inheritance hierarchy.
class A
{
public:
virtual void Foo(int i) { printf("A::Foo(int i)\n"); }
void Foo(int a, int b) { Foo(a + b); }
};
class B : public A
{
public:
void Foo(int i) override { printf("B::Foo(int i)\n"); }
};
class C : public B
{
public:
void Bar() { Foo(1, 2); } //error C2660: function does not take two arguments
};
A has two methods named Foo with a different number of parameters. Only one of them is virtual.
B overrides the virtual method.
C tries to call the non-virtual method and encounters an error.
Calling the method as A::Foo(1, 2) does work fine.
Question:
Why can't the compiler deduce that the correct method is found on A?
It seems odd we would have to explicitly add A:: in a call such as:
C c;
c.A::Foo(1, 2);
Because the member function named Foo is found at the class scope of B, and then name lookup stops, so the Foo in class A is not visible, and won't be considered for overload resolution, even if the version in class A is more appropriate. It is name hiding.
You can use using to introduce them into the same scope, and make overload resolution work as you expect. Such as:
class C : public B
{
using A::Foo;
using B::Foo;
public:
void Bar() { Foo(1, 2); }
};
See Unqualified name lookup
LIVE

Compiler error when overriding virtual methods

Using VC71 compiler and get compiler errors, that i don't understand.
Here comes the example
class A
{
public:
virtual int& myMethod() = 0;
virtual const int& myMethod()const = 0;
};
class B: public A
{
public:
// generates: error C3241: 'const int &B::myMethod(void)' : this method was not introduced by 'A'
virtual int& A::myMethod();
// error C2555: 'B::myMethod': overriding virtual function return type differs and is not covariant from 'A::myMethod'
virtual const int& A::myMethod() const;
};
when i switch order of both method definitions in B then I see a different compiler error:
class B: public A
{
public:
// error C3241: 'const int &B::myMethod(void)' : this method was not introduced by 'A'
virtual const int& A::myMethod() const;
// error C2556: 'int &B::myMethod(void)' : overloaded function differs only by return type from 'const int &B::myMethod(void)'
// error C2373: 'B::myMethod' : redefinition; different type modifiers
virtual int& A::myMethod();
// error C2555: 'B::myMethod': overriding virtual function return type differs and is not covariant from 'A::myMethod'
};
however, if I omit the A:: stuff then i don't get any compiler error:
class B: public A
{
public:
virtual int& myMethod();
virtual const int& myMethod() const;
};
So, what exactly does A:: in front of my method names and why do i see these diverse compiler errors? Any explanation welcome!
class B: public A
{
public:
virtual const int& myMethod() const;
virtual int& myMethod();
};
Remove the A:: in B's definition, and it works well :)
EDIT: missed something in the question...
The :: is used to indicate the scope. You use it either with namespaces or classes to explicitly qualify where to look for the symbol afterwards.
Used in conjunction with methods, it means that you want to precise which method calls, for example:
struct A { int getInt(); }
struct B: public A { int getInt(); }
B b;
b.A::getInt(); // calls A::getInt, not B::getInt
This is completely out of order for a method declaration, the method is declared within a scope and naturally belongs to this scope:
namespace foo
{
int bar(); // full name is foo::bar
}
struct Foo
{
static int bar(); // full name is Foo::bar
};
However, it's useful when referring to the mode:
using foo::bar;
int a = bar(); // calls foo::bar because we asked the compiler
// to import it in the current scope
Or as we already seen, to directly invoke the method:
int B::getInt() // definition outside the class
// we need to specify what we define
{
return this->A::getInt() + 1; // call A::getInt, without precising it
// we would have a stack overflow
}
Hope this helps.
The A:: signifies that you're calling a function from A. Here's an example of why you'd want to use A::
class A{
public:
int m_val;
};
class B{
public:
int m_val;
};
class C: public A, public B{}
Now when I want to set a value for m_val in C, I'd have to do:
C myC;
myC::A::m_val = 4;
so that the compiler doesn't get confused as between what variable you are accessing.
You're not supposed to scope function declarations inside a class declaration. Error messages are not specified in the C++ standard. So, each compiler will obviously produce different messages for something this bizarre.
I assume you're doing something like this to handle multiple inheritance, i.e:
class A
{
public:
virtual int& myMethod() = 0;
};
class A2
{
public:
virtual int& myMethod() = 0;
};
class B: public A, public A2
{
public:
virtual int& A::myMethod();
virtual int& A2::myMethod();
};
But it doesn't work that way. B can only have one myMethod(). See here:
http://www.cprogramming.com/tutorial/multiple_inheritance.html
It looks to me as though you've tried moving a .cpp file contents into a .h file? Those scope declarations would make sense in the .cpp definition file, but shouldn't be there in the .h declaration (as others have alrady pointed out).
// generates: error C3241: 'const int &B::myMethod(void)' : this method was not introduced by 'A'
virtual int& A::myMethod();
So here you're saying you're using a virtual function which is implementing an interface function which is defined elsewhere. By putting A:: in front of it you're saying that your function is overriding myMethod which is defined in A. If you had two base classes (B and C for arguments sake) which both have a function with the same name, you might use virtual B::ThatFunction() to override B's imlpementation or virtual C::ThatFunction() to override C's implementation.
Removing all the A::'s in the A class will fix your compile problems.

C++ member function virtual override and overload at the same time

If I have a code like this:
struct A {
virtual void f(int) {}
virtual void f(void*) {}
};
struct B : public A {
void f(int) {}
};
struct C : public B {
void f(void*) {}
};
int main() {
C c;
c.f(1);
return 0;
}
I get an error that says that I am trying to do an invalid conversion from int to void*. Why can't compiler figure out that he has to call B::f, since both functions are declared as virtual?
After reading jalf's answer I went and reduced it even further. This one does not work as well. Not very intuitive.
struct A {
virtual void f(int) {}
};
struct B : public A {
void f(void*) {}
};
int main() {
B b;
b.f(1);
return 0;
}
The short answer is "because that's how overload resolution works in C++".
The compiler searches for functions F inside the C class, and if it finds any, it stops the search, and tries to pick a candidate among those. It only looks inside base classes if no matching functions were found in the derived class.
However, you can explicitly introduce the base class functions into the derived class' namespace:
struct C : public B {
void f(void*) {}
using B::f; // Add B's f function to C's namespace, allowing it to participate in overload resolution
};
Or you could do this:
void main()
{
A *a = new C();
a->f(1); //This will call f(int) from B(Polymorphism)
}
Well I think first of all you did not understand what virtual mechanism or polymorhism. When the polymorphism is achieved only by using object pointers. I think you are new to c++. Without using object pointers then there is no meaning of polymorphism or virtual keyword use base class pointer and assign the desired derived class objects to it. Then call and try it.

C++ overload resolution [duplicate]

This question already has answers here:
Function with same name but different signature in derived class not found
(2 answers)
Closed 8 years ago.
Given the following example, why do I have to explicitly use the statement b->A::DoSomething() rather than just b->DoSomething()?
Shouldn't the compiler's overload resolution figure out which method I'm talking about?
I'm using Microsoft VS 2005. (Note: using virtual doesn't help in this case.)
class A
{
public:
int DoSomething() {return 0;};
};
class B : public A
{
public:
int DoSomething(int x) {return 1;};
};
int main()
{
B* b = new B();
b->A::DoSomething(); //Why this?
//b->DoSomething(); //Why not this? (Gives compiler error.)
delete b;
return 0;
}
The two “overloads” aren't in the same scope. By default, the compiler only considers the smallest possible name scope until it finds a name match. Argument matching is done afterwards. In your case this means that the compiler sees B::DoSomething. It then tries to match the argument list, which fails.
One solution would be to pull down the overload from A into B's scope:
class B : public A {
public:
using A::DoSomething;
// …
}
Overload resolution is one of the ugliest parts of C++
Basically the compiler finds a name match "DoSomething(int)" in the scope of B, sees the parameters don't match, and stops with an error.
It can be overcome by using the A::DoSomething in class B
class A
{
public:
int DoSomething() {return 0;}
};
class B : public A
{
public:
using A::DoSomething;
int DoSomething(int x) {return 1;}
};
int main(int argc, char** argv)
{
B* b = new B();
// b->A::DoSomething(); // still works, but...
b->DoSomething(); // works now too
delete b;
return 0;
}
No, this behaviour is present to ensure that you don't get caught out inheriting from distant base classes by mistake.
To get around it, you need to tell the compiler which method you want to call by placing a using A::DoSomething in the B class.
See this article for a quick and easy overview of this behaviour.
The presence of a method in a derived class hides all methods with the same name (regardless of parameters) in base classes. This is done to avoid problems like this:
class A {} ;
class B :public A
{
void DoSomething(long) {...}
}
B b;
b.DoSomething(1); // calls B::DoSomething((long)1));
than later someone changes class A:
class A
{
void DoSomething(int ) {...}
}
now suddenly:
B b;
b.DoSomething(1); // calls A::DoSomething(1);
In other words, if it didn't work like this, a unrelated change in a class you don't control (A), could silently affect how your code works.
This has something to do with the way name resolution works. Basically, we first find the scope from which the name comes, and then we collect all overloads for that name in that scope. However, the scope in your case is class B, and in class B, B::DoSomething hides A::DOSomething:
3.3.7 Name hiding [basic.scope.hiding]
...[snip]...
3 In a member function definition, the declaration of a local name hides
the declaration of a member of the class with the same name; see
basic.scope.class. The declaration of a member in a derived class
(class.derived) hides the declaration of a member of a base class of
the same name; see class.member.lookup.
Because of name hiding, A::DoSomething is not even considered for overload resolution
When you define a function in a derived class then it hides all the functions with that name in the base class. If the base class function is virtual and has a compatible signature then the derived class function also overrides the base class function. However, that doesn't affect the visibility.
You can make the base class function visible with a using declaration:
class B : public A
{
public:
int DoSomething(int x) {return 1;};
using A::DoSomething;
};
That's not overloading! That's HIDING!
When searching up the inheritance tree for the function to use, C++ uses the name without arguments, once it has found any definition it stops, then examines the arguments. In the example given, it stops in class B. In order to be able to do what you are after, class B should be defined like this:
class B : public A
{
public:
using A::DoSomething;
int DoSomething(int x) {return 1;};
};
The function is hidden by the function with the same name in the subclass (but with a different signature). You can unhide it by using the using statement, as in using A::DoSomething();