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

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

Related

How to call an abstract function with an abstract class

I want define a function in an abstract class which calls a abstract (virtual) function. But when I inherit from the abstract class this function is not inherited:
class A {
public:
virtual void f(int t) = 0;
void f() {
f(0);
}
};
class B : public A {
public:
void f(int t) override { }
// using A::f; // uncomment to fix the problem
};
int main() {
B b;
b.f(0); // works
b.f(); // error: no matching function for call to ‘B::f()’
}
Why doesn't this work? The workaround is to use using A::f, but why is A::f() not inherited?
It doesn't work because B does not have an f(), only an f(int).
If B did not have any function named f, then the superclass would be searched for a matching function, with overload resolution taking place. But because the subclass, B, does already have a function named f, the superclass is not searched, and the overload resolution happens in B.
This is what the using keyword is for, to make the superclass's f() a part of B's namespace. The answer here is, really, "that's because this is how C++ works".

Why can't I override inherited function?

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.

Hiding of all overloaded methods in base class

recently i came to know this - if a derived class redefines base class member method(s) then all the base class methods with same name become hidden in derived class.
#include<iostream>
using namespace std;
class Base
{
public:
int fun()
{
cout<<"Base::fun() called";
}
int fun(int i)
{
cout<<"Base::fun(int i) called";
}
};
class Derived: public Base
{
public:
int fun()
{
cout<<"Derived::fun() called";
}
};
int main()
{
Derived d;
d.fun(5); // Compiler Error
return 0;
}
Error :
In function 'int main()':
Line 30: error: no matching function for call to 'Derived::fun(int)'
compilation terminated due to -Wfatal-errors.
but just wanna know the reason behind it? why is it not calling fun(int i) method of Base Class since Derived class is derived from Base
The fundamental reason is to make code more robust.
struct Base {
};
struct Derived : Base {
void f(long);
void g() { f(3); } // calls Derived::f
}
Now suppose Base is defined in a library, and you get an update to that library and the update changes the definition of Base:
struct Base {
void f(int);
};
Now suppose that searches for overloaded functions didn't stop when a name was found. In that case, Derived::g would call Base::f instead of Derived::f, and your derived class would quietly do something completely different from what it did before, and different from what it was designed and documented to do.
You've already discovered that derived-class overloads will shadow (prevent the visibility of) base-class methods by the same name but different parameters. Let's just claim this was done for some historical or perceived safety reason, and look at a fix:
class Derived: public Base
{
public:
using Base::fun; // expose the base-class method
int fun()
{
cout<<"Derived::fun() called";
}
};

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.