Jump to content
  • Advertisement
Sign in to follow this  
yacwroy

C++cast function pointer to func ptr with return type = base class of old return type

This topic is 3818 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi I notice this isn't allowed by g++. Should it be?
class A {};
class B : public A {};
B foo();
A (*fp)() = foo;

It seems to me that this couldn't ever cause problems, and it would be a good way to express polymorphism. foo() will always return a B, which is an A. Thus fp will always return an A. Also, shouldn't the following be legal?
class A {};
class B : public A {}
void foo(A a);
void (*fp)(B b) = foo;

Values passed to foo() by fp will always be B's, which are A's. foo() can take any A. Anyone else think that this should be legal? (Or anyone know if it is legal and somehow g++ isn't doing it (perhaps my bad)).

Share this post


Link to post
Share on other sites
Advertisement
From a language theory standpoint, it should work. A function which returns a Derived reference is, by definition, returning a Base reference. Most sane languages will allow this.

However, in C++, things don't work this way. A Derived reference is not a Base reference, it can only be converted to a Base reference by using the appropriate type conversion (which may be implicit in some cases).

To give a simple example, in most implementations of the standard, if Derived has two base classes, BaseOne and BaseTwo, then a pointer-to-Derived will need to be offset by the size of BaseOne to be converted to a pointer-to-BaseTwo (which would point to the BaseTwo part of the Derived object). This cast must be done manually, hence a function-returning-a-pointer-to-Derived cannot be manipulated as a function-returning-a-pointer-to-BaseTwo.

Share this post


Link to post
Share on other sites
Firstly, polymorphism doesn't work in C++ if you pass and return objects by value.

To make the first example support polymorphism you might write:


class A {...};
class B: public A {...};
A* foo() {... return new B; }




(A function returning a pointer to base class may well actually return a pointer to a derived class.)

In the second example, why do you think you need to cast the function pointer? Can't you do it like this?


class A {...};
class B: public A {...};
void foo(const A&) {...}

...
void (*fp)(const A&) = foo;
B b;
fp(b);






Or to provide a more complete comparison of what you are trying to do and how polymorphism works in C++.


#include <iostream>

struct A
{
virtual void foo() const { std::cout << "A::foo()\n"; }
};

struct B: public A
{
virtual void foo() const { std::cout << "B::foo()\n"; }
};

void with_slicing(A a)
{
a.foo();
}

void polymorphic(const A& a)
{
a.foo();
}

int main()
{
B b;
with_slicing(b);
polymorphic(b);

void (*fp1)(B) = reinterpret_cast<void(*)(B)>(with_slicing);
void (*fp2)(const A&) = polymorphic;
fp1(b);
fp2(b);
}




Your approach can be made to compile with a reinterpret_cast (which should make you very suspicious). However, how could that cast possibly affect the function with_slicing itself, so that it would think that the argument is actually of type B?

Share this post


Link to post
Share on other sites
Quote:
Original post by visitor
In the second example, why do you think you need to cast the function pointer? Can't you do it like this?


If he were, for instance, manipulating a container of several function pointers.

Of course, one should be using boost::function for that instead [wink] but the theoretical question is still relevant.

Share this post


Link to post
Share on other sites
(LATE-EDIT) OK yes you're both right thanks. I just woke up as you'll find out if you read on :P.

(LATE-EDIT) Now I'm really confused. I tried recompiling my examples and the 1st one now compiles. I swear it didn't before.





ToohrVyk: Thanks I had forgotten about MI.

however, you might just be able to get around this with a real clever compiler that creates an intermediate function which simply calculates *((&B)->A) (or something like that) - ie, just offsets the reference - then calls the function. i.e.


class Q { int q; };
class A {};
class B : public Q, public A {};

B foo();

// Hidden code never seen by coder.
A __cpp_autogenerated_hidden_func__() { return foo(); }
A (*fp)() = __cpp_autogenerated_hidden_func__();
// Which is generated when the user types A (*fp)() = foo;
// (LATE-EDIT) This assumes there is a A::A(const A&) which there shouldn't be for a polymorphic class.


// You should be able to do:
if(foo != fp) throw Grenade; // Not sure, should that be *foo, or *fp? You get the idea.




visitor:
I was actually using pointers when g++ barfed at me. Seems it don't like being passed by pointer either.

For the 2nd example:

class A {};
class B : public A {}
void foo(A a);
void bar(B b);
B bb;
void (*fp)(B b) = foo;
fp(bb);
fp = bar;
fp(bb);



IE, the function pointer may at other times refer to a function that requires the parameter to be a B.


For part 3: I compiled and got:

A::foo()
B::foo()
A::foo()
B::foo()



******************* Then I woke up. ********************

Yes sorry I should be using references or pointers.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!