I have a base class which has a couple of overloaded versions of a member function. However, I found that I cannot access these methods from the derived class.
#include <iostream>
usingnamespace std;
class A
{
public:
virtualvoid speak() { this->speak(0); }
virtualvoid speak(int i)=0;
};
class B : public A
{
public:
virtualvoid speak(int i) { std::cout << "b says " << i << std::endl; }
};
int main()
{
B b;
b.speak(10);// ok.
b.speak();// error: "no matching function for call to ‘B::speak()’"
A& a = b;
a.speak();//ok.
return 0;
}
If I understand inheritance correctly then B should be able to use all of As public methods. Does anyone know why this does not work? And can suggest a solution?
I'm not definately sure if you can create an abstract class and then define an implementation for a member function within that class; do not hold me to it. Also, do you realise that the implementation is just calling line 9 anyway?
It doesn't look like a problem with you're inheritance rather your polymorphism.
"The main difference between an abstract base class and a regular polymorphic class is that because in abstract base classes at least one of its members lacks implementation we cannot create instances (objects) of it.
"
I think it looks fine, there's something else going on here (member hiding?). Try adding "using A::speak();" in the definition of B and see what happens... I'm just taking a blind stab at it; I don't know exactly what's happening here and I'm not about to start compiling and trying things. :P
EDIT: Curiosity got me... I compiled it and "using A::speak;" works (no parentheses). I'd like to hear a nice explanation of why it is necessary, though.
Is there a particular reason to say this->speak(0); instead of speak(0); (other than perhaps making it clear to the reader that speak() is a member function)?
On second glance line 15 should not be virtualvoid speak but should be void speak As morecm states below, both ways are actually syntactically correct, I just tend not to continue to use the keyword after and forgot; my bad!
#include <iostream>
usingnamespace std;
class A
{
public:
virtualvoid speak()=0;
};
class B : public A
{
public:
void speak() { this->speak(0); }
void speak(int i) { std::cout << "b says " << i << std::endl; }
};
int main()
{
B b;
b.speak(10);// b says 10
b.speak();// b says 0
A& a = b;
a.speak();// b says 0
cin.get();
return 0;
}
Is there a particular reason to say this->speak(0); instead of speak(0); (other than perhaps making it clear to the reader that speak() is a member function)?
There are some contexts (involving templates) in which this could make a difference but in this case they are both the same.
On second glance line 15 should not be virtual void speak but should be void speak
Either way is syntactically correct. The function was declared virtual and will be virtual in all subclasses anyway.
This -> b.speak(); is a call of a member function from a B object. No virtual table looking-up takes place. It simply doesn't work because declaring a derived version of speak overrides all base versions with the same name.
EDIT: I don't really know how the virtual table works but this is my guess... This -> a.speak(); makes the compiler take a look at the virtual table. The choices are: void A::speak(void), void A::speak(int) and void B::speak(int). Only the first one has the desired signature and is thus called even if there is no (caller) type matching. That, in turn, calls void B::speak(int) after another look at the virtual table.
@all: the fact that A is an abstract class is an artifact of the original code than I condensed this down into to simplify the problem. I still see the problem when A isn't abstract.
@m4ster r0shi :
It simply doesn't work because declaring a derived version of speak overrides all base versions with the same name.
Yes, it works when I change the name (eg void speak(int i) to void anotherSpeak(int i). So if I understand correctly, when you override a function in a Derived class, then you are required to override every version that has the same name?
This seems like odd behavior to me. I always thought that overloaded functions, even though they have the same name in your code, actually get assigned very different names by the compiler. So just as a normal call would treat them as entirely separate entities, so should a virtual table look-up.
EDIT: Curiosity got me... I compiled it and "using A::speak;" works (no parentheses). I'd like to hear a nice explanation of why it is necessary, though.
My understanding is that as A is has a pure virtual function, an A can not be instantiated in the construction of a B. Therefore none of the functions from an A are available to the B. The Using declaration allows the 'importing' of the function into the B class.
My understanding is that as A is has a pure virtual function, an A can not be instantiated in the construction of a B. Therefore none of the functions from an A are available to the B. The Using declaration allows the 'importing' of the function into the B class.
Now this is an interesting concept. This basically would mean that abstract base classes are never instantiated, right? Can't you define a constructor and verify that it runs during construction of its subclasses, though?
AFAIK It doesn't have anything to do with the function being virtual. The same thing happens even if nothing in A or B are virtual.
It's just one of those weird things in C++. I never understood the logic behind it either.
EDIT:
Probably it's just a thing to speed up compile time. When you call b.speak(); the compiler looks at the functions in B to see if there's a matching speak() function.
If speak() exists, it knows it doesn't have to search any parent classes, and can stop looking for the function.
If speak() doesn't exist, then it has to start searching parent classes.
This way parent classes are only searched where necessary, instead of being searched for every single function call, which probably shaves a bit off compile time.
Actually, thinking about it, what I said does not make much sense. If you had a function with a different name, say A::Test(), this would be available in the derived class. Must be something to do with overload resolution, I'm going to have to look into this.
Probably it's just a thing to speed up compile time.
I don't think the "saves compile time" theory can explain it. The reason being that it should be searching for a function with the right name and arguments. If it finds one in B with the same name but different arguments then it can only do one of two things. (1) check the parents for matches or (2) return an error.
If you choose (2) you don't really save time in this example, because you are always going to return an error.
But you are probably right that there is some technical reason as to why it works this way.
EDIT: actually having thought about it a little more, it would save compile time. Because of the way overload resolution works (which I just Googled because I didn't previously know) it gets a list of all accessible functions of the same name to start off with. So if it had to check the parents all of the time then this would slow down the process.
SECOND EDIT: And "overload resolution" were just the right keywords to be searching the web to help understand this problem, thanks Grey Wolf.
One of the reasons I came across was that this behaviour was "to ensure that you don't get caught out inheriting from distant base classes by mistake." And they suggest bigearsbilly's solution as the way around it.