I've got a situation where it seems like the compiler isn't finding the base class definition/implementation of a virtual function with the same name as another member function.
struct One {};
struct Two {};
struct Base
{
virtual void func( One & );
virtual void func( Two & ) = 0;
};
struct Derived : public Base
{
virtual void func( Two & );
};
void Base::func( One & )
{}
void Derived::func( Two & )
{}
// elsewhere
void this_fails_to_compile()
{
One one;
Derived d;
d.func( one );
}
I'm using Visual C++ 2008. The error message is:
error C2664: 'Derived::func' : cannot convert parameter 1 from 'One' to 'Two &'
I would have thought that the type based dispatch would work and call the defined base class function. If I add a Derived::func( One & ) it does compile and get called correctly, but in my situation, that version of the function can be done in the base class and usually derived classes don't need to implement it themselves. I'm currently working around it by putting a differently named, non-virtual function in the base class that forwards the call to function causing the problem:
// not virtual, although I don't think that matters
void Base::work_around( One & one )
{
func( one );
}
That works but is obviously less than ideal.
What inheritance and/or name-hiding rule am I missing here?
You are hiding the method in the derived class. The simplest solution is to add a using declaration to the derived class.
struct Derived : public Base
{
using Base::func;
virtual void func( Two & );
};
The issue is that when the compiler tries to lookup the func identifier in the call d.func(one) it has to do that from Derived upwards, but it will stop in the first context where it finds the func identifier, which in this case it is Derived::func. No further lookup is performed and the compiler was seeing only the Derived::func( Two& ).
By adding the using Base::func; directive, when the compiler sees the Derived definition it brings all of Base::func declarations into scope, and it will find that there is a Base::func( One & ) that was not overridden in Derived.
Note also that if you were calling through a reference to Base, then the compiler would find both overloads of func and would dispatch appropriately each one to the final overrider.
Derived d;
Base & b = d;
b.func( one ); // ok even without the 'using Base::func;' directive
You hide func(One&) function in Derived. You could use fully qualified name:
d.Base::func( one );
Related
A class Base, which I have no control over, has a function that accepts a member pointer to any class function. It is meant to be used as follows:
class Derived : public Base {
void bindProperties() {
Base::bindProperty("answer", &Derived::getAnswer);
}
int getAnswer() const { return 42; }
};
Some way (that I neither know nor care about), Base stores this pointer and later allows me to call Derived::get("answer") (of course, this is a simplified situation).
The down side is, that we tried to be smart in the past, and used multiple inheritance:
class ICalculator {
virtual int getAnswer() const;
};
template<class T>
class LifeAndUniverseCalculator : public T, public ICalculator {
virtual int getAnswer() const /* override */ { return 42; }
void bindProperties() {
T::bindProperty("answer", &ICalculator::getAnswer); // (*)
}
};
thinking that the multiple inheritance is not bad, as long as we only use it to inherit an interface and only have one "concrete" base class.
The templating is because sometimes we want to derive from Base and sometimes from one of its derived classes (which I also don't have access to) - if that is irrelevant you can pretend I wrote Base instead of T and drop the template.
Anyway, the problem I am having now, is that when I call
LifeAndUniverseCalculator calc;
calc.bindProperties();
int answer = calc.get("answer");
I get gibberish. I figured it may be something with pointers into vtables, so I tried replacing
T::bindProperty("answer", &ICalculator::getAnswer);
by
T::bindProperty("answer", &LifeAndUniverseCalculator::getAnswer);
hoping that it would calculate the offset correctly, but clearly that does not work (as you have figured out by now, I am really second guessing how this all works).
I thought of some options, such as
getting rid of the multiple inheritance and putting everything in ICalculator directly in LifeAndUniverseCalculator (it's the only derived class)
creating wrapper functions for all ICalculator stuff in LifeAndUniverseCalculator, e.g. LifeAndUniverseCalculator::Calculator_GetAnswer just calls ICalculator::GetAnswer.
I'd like to know
Preferably, is there a way to fix the line marked with (*) in a simple way?
If not, what is the best solution (one of the alternatives above, or something else)?
If I were able to contact the author of class Base and they would be willing and able to change their class, what specifically would I need to ask, if you are able to say something sensible based on my description.
If you need a MCVE, there is one which I think captures the problem on IDEOne.
In your MCVE, the function A::bindFunction (analogous to Base::bindProperty in your simplified code) force casts a member of function of B to a member function of A. This strikes me as the root problem. This can be fixed by changing the type of A::f to be an std::function<int(void)>:
class A
: public ABase {
public:
// int a, b;
class Unknown{};
typedef int(A::*Function)();
template<typename T, typename Func>
void bindFunction(T* owner, Func myf) {
f = std::bind(myf,owner);
}
int call() {
return f();
}
//Function f;
std::function<int(void)> f;
};
...
class Combined
: public A, public B {
public:
Combined(int value) : B(value), A() {}
virtual void /*A::*/bind() /* override */ {
A::bindFunction( this, &Combined::getValue );
}
};
With only this change, your MCVE works, printing out
The answer to Life, The Universe and Everything is 42
However, I recognize that the code that I changed belongs to a class that you've explicitly mentioned that you cannot modify. Is this indeed what Base does -- it casts member functions of other classes to member functions of itself? (Or perhaps, while my fix makes the code work, I've misidentified the problem).
This question already has answers here:
Why does an overridden function in the derived class hide other overloads of the base class?
(4 answers)
Closed 5 years ago.
Suppose I have the following classes:
class Base
{
public:
virtual void myMethod()
{
}
virtual void myMethod(int x)
{
}
};
class Derived : public Base
{
};
In this situation the following code compiles just fine.
int main(void)
{
Derived obj;
obj.myMethod();
return (0);
}
The problem arises when I try to override one of myMethods like below.
class Derived : public Base
{
public:
virtual void myMethod(int x)
{
}
};
Now the code won't compile and gives the error:
error C2660: 'Derived::myMethod' : function does not take 0 arguments
I have overridden one of the overloaded functions and apparently this has hidden the other one from Derived class. To get rid of the error I have to override all the overloads. This is against my expectation and doesn't seem rational to me. Why does this code behave this way?
The problem can be reproduced here.
Indeed, declaring a function in one scope hides anything with the same name in a wider scope, so your override in the derived class hides the overload in the base class.
This is usually not a problem, since you'd usually interact with polymorphic classes via the base class; and usually what you want, since it prevents changes to the base class from unexpectedly changing the behaviour of code that does interact with the derived class.
But you can easily bring it back into the derived class's scope if you want:
using Base::myMethod;
or refer to the function by qualified name:
obj.Base::myMethod();
your compiler is 100% right.
you overloaded your function to take an integer as argument, then this function hid all of the base class function - so obj calls myMethod(int) be default , yet you don't provide your function an integer.
if you fix your code to be
obj.myMethod(4);
the problem solved.
when overriding a function in the derived class - it hides all the other base class overloads. one can still call the base class with this syntax :
obj.Base::myMethod();
In more in depth answer , this is WHY it happens.
first of all, we need to understand HOW the compiler compiles Object oriented code. remember - the functions compiles into assembly commands and they sit in the code segment. the variables compiles into rows of memory that sit wither in the stack , heap or data segments. functions sits in on part of the application , the variables in a complete different areas. how does the compiler compile a class with variables AND functions? well, it doesn't. the idea goes like this:
let's say a have a class named X with some variables and some functions
1) take all the member functions and bring them out of the class
2) add another argument to each-now-globally-declared functions - const X* this
3) each time you see the syntax x.someFunc(args..) change it to be someFunc(args..,&x)
4) in the functions - if you don't recognize a symbol - try attaching it a this-> and see if you can compile this
5) compile X as C struct and the other as C functions
6)do the same for derived classes
(of course , there is the virtual table issue , but let's stop here)
IN YOUR EXAMPLE:
the psuedo code that might represent the compiler parsed-code is
struct Base{}
struct Derived{}
void myMethod(const Base* this);
void myMethod(int x,const Base* this);
void myMethod(int x, const Derived* this);
//what you tried to do is :
myMethod (&obj);
but the compiler can't find any function that matches these arguments!
this is not very intuitive for someone who don't initially knows how object oriented compiles, but it makes more sense after understanding this compiling procedure.
By overriding the function in Derived class you hide all overloaded implementations of that function name existing in Base class.
Therefore overriding void Base::myMethod(int) with void Derived::myMethod(int) generates code only for void Derived::myMethod(int) and doesn't for void Derived::myMethod().
As mentioned before you can call Base's function explicitly:
obj.Base::myMethod().
I would like to implement interactions between two objects whose types are derived from a common base class. There is a default interaction and specific things may happen once objects of the same type interact.
This is implemented using the following double dispatch scheme:
#include <iostream>
class A
{
public:
virtual void PostCompose(A* other)
{
other->PreCompose(this);
}
virtual void PreCompose(A* other)
{
std::cout << "Precomposing with an A object" << std::endl;
}
};
class B : public A
{
public:
virtual void PostCompose(A* other) // This one needs to be present to prevent a warning
{
other->PreCompose(this);
}
virtual void PreCompose(A* other) // This one needs to be present to prevent an error
{
std::cout << "Precomposing with an A object" << std::endl;
}
virtual void PostCompose(B* other)
{
other->PreCompose(this);
}
virtual void PreCompose(B* other)
{
std::cout << "Precomposing with a B object" << std::endl;
}
};
int main()
{
A a;
B b;
a.PostCompose(&a); // -> "Precomposing with an A object"
a.PostCompose(&b); // -> "Precomposing with an A object"
b.PostCompose(&a); // -> "Precomposing with an A object"
b.PostCompose(&b); // -> "Precomposing with a B object"
}
I have two, unfortunately quite different questions regarding this code:
Do you think this is a reasonable approach? Would you suggest something different?
If I omit the first two B methods, I get compiler warnings and errors that the last two B methods hide the A methods. Why is that? An A* pointer should not be cast to a B* pointer, or should it?
Update: I just found out that adding
using A::PreCompose;
using A::PostCompose;
makes the errors and warnings vanish, but why is this necessary?
Update 2: This is neatly explained here: http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9, thank you. What about my first question? Any comments on this approach?
Double dispatch is usually implemented differently in C++, with the base class having all different versions (which makes it a maintenance nightmare, but that is how the language is). The problem with your attempt to double dispatch is that dynamic dispatch will find the most derived type B of the object on which you are calling the method, but then the argument has static type A*. Since A does not have an overload that takes B* as argument, then the call other->PreCompose(this) will implicitly upcast this to A* and you are left with single dispatch on the second argument.
As of the actual question: why is the compiler producing the warnings? why do I need to add the using A::Precompose directives?
The reason for that are the lookup rules in C++. Then the compiler encounters a call to obj.member(), it has to lookup the identifier member, and it will do so starting from the static type of obj, if it fails to locate member in that context it will move up in the hierarchy and lookup in the bases of the static type of obj.
Once the first identifier is found, lookup will stop and try to match the function call with the available overloads, and if the call cannot be matched it will trigger an error. The important bit here is that lookup will not look further up in the hierarchy if the function call cannot be matched. By adding the using base::member declaration, you are bringing the identifier member from the base class into the current scope.
Example:
struct base {
void foo( const char * ) {}
void foo( int ) {}
};
struct derived : base {
void foo( std::string const & ) {};
};
int main() {
derived d;
d.foo( "Hi" );
d.foo( 5 );
base &b = d;
b.foo( "you" );
b.foo( 5 );
d.base::foo( "there" );
}
When the compiler encounters the expression d.foo( "Hi" ); the static type of the object is derived, and lookup will check all member functions in derived, the identifier foo is located there, and lookup does not proceed upwards. The argument to the only available overload is std::string const&, and the compiler will add an implicit conversion, so even if there could be a best potential match (base::foo(const char*) is a better match than derived::foo(std::string const&) for that call) it will effectively call:
d.derived::foo( std::string("Hi") );
The next expression d.foo( 5 ); is processed similarly, lookup starts in derived and it finds that there is a member function there. But the argument 5 cannot be converted to std::string const & implicitly and the compiler will issue an error, even if there is a perfect match in base::foo(int). Note that this is an error in the call, not an error in the class definition.
When processing the third expression, b.foo( "you" ); the static type of the object is base (note that the actual object is derived, but the type of the reference is base&), so lookup will not search in derived but rather start in base. It finds two overloads, and one of them is a good match, so it will call base::foo( const char* ). The same goes for b.foo(5).
Finally, while adding the different overloads in the most derived class hide the overloads in the base, it does not remove them from the objects, so you can actually call the overload that you need by fully qualifying the call (which disables lookup and has the added side effect of skipping dynamic dispatch if the functions were virtual), so d.base::foo( "there" ) will not perform any lookup at all and just dispatch the call to base::foo( const char* ).
If you had added a using base::foo declaration to the derived class, you would add all the overloads of foo in base to the available overloads in derived, and the call d.foo( "Hi" ); would consider the overloads in base and find that the best overload is base::foo( const char* );, so it will actually be executed as d.base::foo( "Hi" );
In many cases, developers are not always thinking on how the lookup rules actually work, and it might be surprising that the call to d.foo( 5 ); fails without the using base::foo declaration, or worse, that the call to d.foo( "Hi" ); is dispatched to derived::foo( std::string const & ) when it is clearly a worse overload than base::foo( const char* ). That is one of the reasons why compilers warn when you hide member functions. The other good reason for that warning is that in many cases when you actually intended to override a virtual function you might end up mistakenly changing the signature:
struct base {
virtual std::string name() const {
return "base";
};
};
struct derived : base {
virtual std::string name() { // missing const!!!!
return "derived";
}
}
int main() {
derived d;
base & b = d;
std::cout << b.name() << std::endl; // "base" ????
}
A small mistake while trying to override the member function name (forgetting the const qualifier) means that you are actually creating a different function signature. derived::name is not an override to base::name and thus a call to name through a reference to base will not be dispatched to derived::name!!!
using A::PreCompose;
using A::PostCompose;
makes the errors and warnings vanish, but why is this necessary?
If you add new functions to your derived class with same name as your base class contains and if you don't override the virtual functions from base class, then new names hide the old names from the base class.
That is why you need to unhide them by explicity writing:
using A::PreCompose;
using A::PostCompose;
Other way to unhide them (in this particular case) is , override the virtual functions from base class which you've done in the code you've posted. I believe that code would compile just fine.
Classes are scopes and the look up in a base class is described as looking up in an enclosing scope.
When looking up overload of a function, looking up in enclosing scope is not done if a function was found in the nested one.
A consequence of the two rules is the behaviour you experimented. Adding the using clauses import the definition from the enclosing scope and is the normal solution.
I wrote the below code in order to explain my issue. If I comment the line 11 (with the keyword "using"), the compiler does not compile the file and displays this error: invalid conversion from 'char' to 'const char*'. It seems to not see the method void action(char) of the Parent class in the Son class.
Why the compiler behave this way? Or have I done something wrong?
class Parent
{
public:
virtual void action( const char how ){ this->action( &how ); }
virtual void action( const char * how ) = 0;
};
class Son : public Parent
{
public:
using Parent::action; // Why should i write this line?
void action( const char * how ){ printf( "Action: %c\n", *how ); }
};
int main( int argc, char** argv )
{
Son s = Son();
s.action( 'a' );
return 0;
}
The action declared in the derived class hides the action declared in the base class. If you use action on a Son object the compiler will search in the methods declared in Son, find one called action, and use that. It won't go on to search in the base class's methods, since it already found a matching name.
Then that method doesn't match the parameters of the call and you get an error.
See also the C++ FAQ for more explanations on this topic.
Surprisingly this is standard behavior. If a derived class declares a method with the same name as a method defined by the base class, the derived class' method hides the base class' one.
See C++ FAQ
A note of caution: The need to use a "using" in this situation is a red flag that your code may be confusing for other developers (after all it confused the compiler!). It is likely that you should rename one of the two methods to make the distinction clear to other programmers.
One possibility:
void action( const char how )
{
takeAction( &how );
}
void action( const char * how )
{
takeAction(how);
}
virtual void takeAction(const char * how) = 0;
If in a derived class any over loaded function is redefined then all the overloaded function in the base class is hidden.
One way to include both the functionality is to avoid function overloading in classes. or
You can use using keyword, as used.
By using using, the names declared in base class are introduced into the namespace of derived class.
Then, when you declare the set of functions in the derived class, they are distinguished from those with identical parameter types in its base class by compilers by the type of the implicit this pointer.
During overload resolution, an argument that needs a class-type conversion, which will happen when a pointer to derived class is converted to a pointer to a base class, is of the lowest priority.
So the two functions with seemingly identical parameter list can be distinguished, and when calling them from an object of the derived type, the one locally declared will be a better (if not exact) match.
I am a newbie and please point out my misunderstanding.
#include<iostream>
using namespace std;
class A
{
int a;
int b;
public:
void eat()
{
cout<<"A::eat()"<<endl;
}
};
class B: public A
{
public:
void eat()
{
cout<<"B::eat()"<<endl;
}
};
class C: public A
{
public:
void eat()
{
cout<<"C::eat()"<<endl;
}
};
class D: public B, C
{
};
int foo(A *ptr)
{
ptr->eat();
}
main()
{
D obj;
foo(&(obj.B)); //error. How do i call with D's B part.
}
The above foo call is a compile time error.
I want to call foo with obj's B part without using virtual inheritance. How do i do that.
Also, in case of virtual inheritance, why the offset information need to be stored in the vtable. This can be determined at the compile time itself. In the above case, if we pass foo with D's object, at compile time only we can calculate the offset of D's A part.
Inheriting twice
With double inheritance you have an ambiguity - the compiler cannot know which of the two A bases do you want to use. If you want to have two A bases (sometimes you may want to do this), you may select between them by casting to B or C. The most appropriate from default casts here is the static_cast (as the weakest available), however it is not realy needed (it is still stronger than your case needs), as you are not casting to a derived type. A custom safe_cast template should do the job:
/// cast using implicit conversions only
template <class To,class From>
inline To safe_cast( const From &from ) {return from;}
main()
{
D obj;
foo(safe_cast<B *>(&obj)); //error. How do i call with D's B part.
}
Compile time types - use templates
Also, in case of virtual inheritance,
why the offset information need to be
stored in the vtable. This can be
determined at the compile time itself.
In the above case, if we pass foo with
D's object, at compile time only we
can calculate the offset of D's A
part.
This is a misconception. The foo function as it is written now has no compile type information about ptr type other than it is A *, even if you pass B * or C*. If you want foo to be able to act based on the type passed compile time, you need to use templates:
template <class TypeDerivedFromA>
int foo(TypeDerivedFromA *ptr)
{
ptr->eat();
}
Virtual Inheritance
Your questions mentions virtual inheritance. If you want to use virtual inheritance, you need to specify so:
class B: public virtual A ...
class C: public virtual A ...
With this the code would compile, but with this solution there is no way you could select between B::A or C::A (there is only one A), therefore this is probably not what you are about.
Virtual functions
Furthermore, your questions seems to be confusing two different concepts, virtual inheritance (which means sharing one base class between two intermediate base classes) and virtual functions (which mean allowing derived class function to be called via base class pointer). If you want the B::eat to be called using A pointer, you can do this without virtual inheritance (actually virtual inheritance would prevent you doing so, as explained above), using virtual functions:
class A
{
int a;
int b;
public:
virtual void eat()
{
cout<<"A::eat()"<<endl;
}
};
If virtual functions are not acceptable for you, the compile time mechanism for this are templates, as explained above.
Use a cast - static_cast is required here to cast up the heirarchy.
main()
{
D obj;
foo(static_cast<B*>(&obj));
}
First of all, obj does not have a member named B. It Inherits from B, which means that it inherits all of B's members as its own.
You can call:
foo(static_cast<B*>(&obj)); to make it work.
I don't think the static_cast will work.
When you are on the foo function, all the compiler knows is that you have a pointer to A, whatever the type you passed as parameter.
If you don't use virtual inheritance, then I think there is no way to call a B function from a pointer to A.