38434

c++ problem with function overloading

Question:

i have a problem with function overloading. I will show you with some simple example:

class A {}; class B : public A{}; void somefunction(A&, A&); void somefunction(B&, B&); void someotherfunction() { ... A& a1 = ... A& a2 = ... ... }

Both a1 and a2 are instances of B but

somefunction(a1,a2);

calls

void somefunction(A&, A&);

What did i do wrong? I mean polymorphism and overloading are for stuff like that, arent they?

edit: Ok now i know it does not work (thanks for your answers).

Any solution how to do this? Without casting.

edit2: <strong><em>Ok left it as it is, with type casting, since something i would like to have is not possible. Thanks all for your help.</em></strong>

Answer1:

Cast them statically so that the compiler knows which one to pick:

void somefunction((B&)a1, (B&)a2);

The reason why you are having this problem is with the program design, not the language. Compiler picks which which function is used based on the types that are passed in. C# will behave in exactly the same way (pretty sure Java will too).

It seems to me that you are implementing polymorphism in the wrong place. somefunction really belongs inside class a and should be virtual. Then whenever it's called on the instance of a at runtime the override in the right class will be called.

So, really it should be something like this:

class a { public: virtual somefunction(a& a2) { //do stuff } } class b : public a { virtual somefunction(a& a2) { b& b2 = (b&)a2; //do stuff } } class c : public b { virtual somefunction(a& a2) { c& c2 = (c&)a2; //do stuff } }

The above solution uses minimal casting inside the virtual function and assumes that the two instance of the same type. This means that b.somefunction(a()) will have undefined behaviour.

A better solution is to rely on C++ <a href="http://en.wikipedia.org/wiki/Run-time_type_information" rel="nofollow">RTTI</a> and use dynamic_cast, which will return NULL if the downcast is not possible.

This problem is known as <a href="http://en.wikipedia.org/wiki/Double_dispatch" rel="nofollow">double dispatch problem</a> and is described in the wikipedia article pretty much as you described it. Furthermore, the only solution that wikipedia gives for <a href="http://en.wikipedia.org/wiki/Multiple_dispatch" rel="nofollow">multiple dispatch</a> is to use dynamic_cast.

<strong>EDIT</strong> OK, this has been bugging me, here is the solution for full double dispatch between a base class and two subclasses. It aint pretty and uses a bit of C++ trickery like friend classes (for better encapsulation actually, rather than the reverse) and forward declarations.

class b; class c; class a { protected: virtual void somefunction(a& a2); //do stuff here virtual void somefunction(b& b2); //delegate to b virtual void somefunction(c& c2); //delegate to c public: virtual void doFunc(a& a2) { a2.somefunction(*this); } friend class b; friend class c; }; class b : public a { protected: virtual void somefunction(a& a2); //do stuff here virtual void somefunction(b& b2); //do stuff here virtual void somefunction(c& c2); //delegate to c public: virtual void doFunc(a& a2) { a2.somefunction(*this); } friend class a; }; class c : public b { protected: virtual void somefunction(a& a2); //do stuff here virtual void somefunction(b& b2); //do stuff here virtual void somefunction(c& c2); //delegate to c public: virtual void doFunc(a& a2) { a2.somefunction(*this); } friend class a; friend class b; }; //class a void a::somefunction(a& a2) { printf("Doing a<->a"); } void a::somefunction(b& b2) { b2.somefunction(*this); } void a::somefunction(c& c2) { c2.somefunction(*this); } //class b void b::somefunction(a& a2) { printf("Doing b<->a"); } void b::somefunction(b& b2) { printf("Doing b<->b"); } void b::somefunction(c& c2) { c2.somefunction(*this); } //class c void c::somefunction(a& a2) { printf("Doing c<->a"); } void c::somefunction(b& b2) { printf("Doing c<->b"); } void c::somefunction(c& c2) { printf("Doing c<->c"); }

Answer2:

The function to call is only determined at run-time for virtual methods, based on the type of the <strong>this</strong> object:

A* a = new B; a->foo(); //calls B::foo (as long as foo is virtual)

The function to call is not resolved at run-time based on the "real" type of a function's arguments.

A* a = new B; X* x = new Y; a->foo(x); //assuming virtual and two overloads, calls B::foo(X*), not B::foo(Y*)

There is no built-in double dispatch mechanism (to select the function to call based on the dynamic types of two objects at the same time), although the pattern can be manually implemented as some posts show.

If you say that you <strong>always know</strong> that the A& will actually be B& and don't want casts, I conclude that the types will be <strike>hard-coded</strike> known at compile-time, so you might try "compile-time polymorphism" instead. (In this case A and B don't even need to be related, as long as they have a suitable interface.)

class A {}; class B {}; class C: public A {}; void somefunction(const A&, const A&); void somefunction(const B&, const B&); template <class T> void someotherfunction() { const T& a1 = T(); const T& a2 = T(); somefunction(a1, a2); } int main() { someotherfunction<A>(); someotherfunction<B>(); //combine with inheritance and it will still be //possible to call somefunction(A&, A&) since //somefunction(C&, C&) is not defined someotherfunction<C>(); }

Now a1 and a2 will <em>really</em> be As in one instantiation and Bs in the other case, as far as selecting the overload is concerned. (I added some consts, because otherwise it would be harder to produce something that binds to non-const references.)

Answer3:

As others have already mentioned, the compiler picks the correct overload - its how the language works.

If you are really sure of what type the instances are, you should just cast. If not, one way you can get around manual type-checking at run-time is <a href="http://en.wikipedia.org/wiki/Double_dispatch" rel="nofollow">double dispatch</a>:

struct A; struct B; struct Base { virtual perform(Base& b) = 0; virtual perform(A& a) = 0; virtual perform(B& b) = 0; }; struct A : Base { virtual perform(Base& b) { b.perform(*this); } virtual perform(A& a) { someFunction(a, *this); } virtual perform(B& b) { someFunction(b, *this); } }; struct B : A { virtual perform(Base& b) { b.perform(*this); } virtual perform(A& a) { someFunction(a, *this); } virtual perform(B& b) { someFunction(b, *this); } }; // ... Base& b1 = foo1(); Base& b2 = foo2(); b1.perform(b2);

Answer4:

what exactly are you trying to do? it looks like you are trying to write a function that does something given two objects, and you want it to do a different thing based on the type of the combination of objects?

remember that even normal polymorphism does "checks" internally.

this is an interesting problem tho,

polymorphism gives you the ability to easily overload the functionality of a function based on the type of ONE object, not two.

what is it EXACTLY that you are trying to do? my best suggestion would be to make it so that each object could perform its own specific stuff separately and then return a common object for common processing:

class Base { virtual SomeComonInterfaceObject DoMySpecialSomething() = 0; } void _doSomething(SomeComonInterfaceObject a, SomeComonInterfaceObject b); void doSomething(Base& o1, Base& o2) { _doSomething(o1->DoMySpecialSomething(), o2->DoMySpecialSomething()); }

if that doesn't suit, you probably just have to check the type and do specifics based on that.

note that even normal polymorphism does "checks" if you are worried about performance, any other language would have to too.

the only way you might be able to get around that is by using templates, and it would probably get real ugly.

would be interesting to know what you are trying to do. also, these doSomething functions, is it always the case that their two parameters are the same type? or do they mix and match?

Answer5:

Yes but C++ decided which function to use at compile time, not at runtime. And at compile time the only thing the compiler sees is (A&, A&) - it cannot know that those are actually instances of B.

Answer6:

You should post more code....what is <br /> A& a1 = ...<br /> A& a2 = ...<br />

Shouldn't you use pointers? If you're storing a1 and a2 as type A then even if they are also B's the A overload gets called. You'd have to dynamic_cast them.

Answer7:

In this case compiler will always call somefunction(A&, A&);. Why would it call somefunction(B&, B&);?

Answer8:

You said in a comment that you're SURE that they are B's.

If that is the case then this is what you want to do.

B a1(); B a2();

If you ever need A's, you can do this (A*)&B. That is an implicit cast and I'm pretty sure it happens at compile time.

Answer9:

Your compiler has chosen what it thinks is the most appropriate overload. a1 and a2 are both declared as references to class A, so they fit the overload which takes references to class A "better" than they fit the other one, since that would require some sort of implicit cast to convert them to class B.

Note also that you can't implicitly upcast that way. If you have a pointer or reference to an instance of the base class (A in this case) then it can't be implicitly converted to a derived class, because in general not all instances of the base class are instances of the derived class (all Bs are As, but not all As are Bs).

You will need to declare them as instances of B before calling the function:

B& b1 = ... B& b2 = ... somefunction(b1, b2);

Answer10:

What i will do is to use a dispatch table to get what i want. Instead of 1 dimensional it may be 2 or 3 dimensional (probably 2). Thanks all for trying to help me!

Recommend

  • ITextSharp and putting rich text in a specific position
  • libobjc.A.dylib objc_msgSend - React Native iOS - How do I read this crash report?
  • C# Nested classes
  • Resharper Rename Fields
  • rails - implementing a simple lock to prevent user's from editing the same data concurrently
  • Fetch MySQL row result to dynamic array
  • Difference between import * as Button and import {Button}
  • How to encapsulate dynamically added elements in Angular 2?
  • How important are classes? (PHP) [closed]
  • Angular - Override CSS of swimlane/ngx-datatable
  • Disable White Vertical Line
  • In a django custom field, what does the SubfieldBase metaclass do?
  • Why the drawPolygon method in Graphics Class abstract and I can still use it
  • CUBA : entity inheritance
  • Java catching exceptions and subclases
  • Calling a second level base class constructor
  • Getting directory of input file (Applescript)
  • Finding parents in a tree hierarchy for a given child LINQ (lambda expression)
  • How to sort things out in ListView?
  • In matplotlib, how do you change the fontsize of a single figure?
  • Spring: No transaction manager has been configured
  • Invalid Date on validation Date of js
  • accepts_nested_attributes_for practical form use for in Rails 3
  • Why use database factory in asp.net mvc?
  • Can someone please explain to me in the most layman terms how to use EventArgs?
  • Object and struct member access and address offset calculation
  • print() is showing quotation marks in results
  • Make VS2015 use angular-cli ng at build time in a .NET project
  • Android fill_parent issue
  • Repeat a vertical line on every page in Report Builder / SSRS
  • Android screen density dpi vs ppi
  • Fetching methods from BroadcastReceiver to update UI
  • Bug in WPF DataGrid
  • Get object from AWS S3 as a stream
  • Symfony2: How to get request parameter
  • Statically linking a C++ library to a C# process using CLI or any other way
  • GridView Sorting works once only
  • WPF Applying a trigger on binding failure
  • python regex in pyparsing
  • java string with new operator and a literal