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".
Related
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
Say I have a base class and a derived class.
class Base {
public:
void A(int x, int y) {do something}
void B() {
A(x,y);
do something;
}
};
class Derived : public Base {
void A() {do something else};
};
Derived derived1;
derived1.B();
The signatures of the functions are different, will the B call the derived A or the base A? Iif it will call the derived B, I guess it will dismiss the parameters?
what if the derived A needed different parameters rather than no parameters, would I have to copy B's entire code into the derived class just to change the way B calls A?
A function's code is always evaluated in the context of the class in which it is defined. This includes determining which function each expression calls. So inside Base::B(), the call A(x, y) is translated by the compiler as a call to Base::A. Even if you later call derived1.B(), it will call derived1 . Base::A (pseudo-syntax).
The only thing which changes this slightly is virtual functions. However, even with them, the rules are similar. Overload resolution (which is basically the process of matching a function name & signature to a call expression) is done in the context of the class where the containing function is defined. If the resolution leads to a virtual function being selected, the virtual call mechanism will then be invoked at runtime to call the appropriate override of that function.
Let's consider this example:
struct Base {
virtual void foo(int);
virtual void bar() { foo(0.0); }
};
struct Derived : Base {
virtual void foo(int);
virtual void foo(double);
};
Derived d;
d.bar();
Even in this example, calling d.bar() will call Derived::foo(int). That's because the call-to-signature matching was done in the context of Base, which only sees foo(int) and employs the implicit conversion from double to int.
Two reasons force Base::B to call Base::A not Derived::A
It's calling A with specific overload: A(int, int)
Base::A and Base::B are not virtual, so it calls Base::A. The code is not polymorphic.
The simplest example to show a how a virtual method works is:
class Base {
public:
virtual void A() {
// do job #1
}
};
class Derived : public Base {
public:
virtual void A() {
// do job #2
}
};
// ...
Derived derived1;
Base *base = &derived1;
base->A(); // <---- It calls `Derived::A()` and does job #2
But, if you write A in B with different parameter (overload it), you have to call it explicitly with actual arguments.
I have a class (B) that inherits another class (A). I want to call a function from class A that has been overridden. I also want to be able to call the overridden function independent of what class inherited the base (say class C : public A , where I want to call C's version of the function.)
Here's an example
class A {
public:
void callF();
virtual void f() {};
};
class B : public A {
public:
void f();
};
void A::callF()
{
//FYI, I want to be able to call this without knowing what the super class is.
f();
}
void B::f()
{
std::cout << "I want this function to be called, but instead the default f() is called.";
}
Edit:
In my real code, I have an std::vector<A> aVector;. Then I would call aVector.push_back(B());. If I called aVector[0].callF();, The default a::f() would be called.
As answered below, I have a problem with slicing.
Your construction:
vector_of_A.push_back( B() );
doesn't store a B in the vector. It constructs a B, then constructs an A from that, then stores that A in the vector. As a consequence, you experience slicing.
See this for more info:
https://stackoverflow.com/a/4403759/8747
Your code is correct.
You may be getting the behavior you observed because your were calling f() or callF() from the constructor of A. That's the only case I can think of where A::f() would get invoked instead of B::f().
Your code works for me with this little test program:
int main()
{
// Instantiate B, and reference it via a base class pointer.
A* b = new B;
b->callF();
delete b;
}
Output:
I want this function to be called, but instead the default f() is called.
When calling a virtual member function within a base class member function, it's the derived member function that will be invoked.
Below program contains two show() functions in parent and child classes, but first show() function takes FLOAT argument and second show() function takes INT argument.
.If I call show(10.1234) function by passing float argument, it should call class A's show(float a) function , but it calls class B's show(int b).
#include<iostream>
using namespace std;
class A{
float a;
public:
void show(float a)
{
this->a = a;
cout<<"\n A's show() function called : "<<this->a<<endl;
}
};
class B : public A{
int b;
public:
void show(int b)
{
this->b = b;
cout<<"\n B's show() function called : "<<this->b<<endl;
}
};
int main()
{
float i=10.1234;
B Bobject;
Bobject.show((float) i);
return 0;
}
Output:
B's show() function called : 10
Expected output:
A's show() function called : 10.1234
Why g++ compiler chosen wrong show() function i.e class B's show(int b) function ?
If you have a function in a derived class that has the same name as a function in the base class, it hides all of the functions in the base class. You either need to rename your function, or use a using declaration in your derived class:
using A::show;
or, you can explicitly call the base class function:
Bobject.A::show(i);
There is no polymorphism involved here. You should declare your functions virtual to make them polymorphic, and make them have the same signature.
Use a using declaration.
class B : public A{
int b;
public:
using A::show;
…
};
You're mixing things:
If you had 2 functions in class A with the following signatures:
void Show(int a);
void Show(float a);
Then the compiles would have chosen the "correct" function.
When you define a name in a derived class, it hides the name from the base class.
You can achieve what you want by adding this to B's definition:
using A::show;
That will let you use both A's show() and B's show().
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.