0

I want to make a function pointer that takes a parameter of the base class. I want to be able to create a function that pointer can point to but have it take a parameter of the derived class. I then want to be able to call the function parameter with the derived class and have it preform a function as if the parameter was the derived class. I want to be able to do something like this:

void(*pointer)(Base);
class Base
{};

class Something : public Base
{
public:
    float f;
    int i;
};

void doSomething(Something s)
{
    //do something
}


int main()
{
    Something s;
    pointer = doSomething;
    pointer(s);

    return 0;
}

Is there anything I can do to make this work in c++?

Kara
  • 6,115
  • 16
  • 50
  • 57
BlueSpud
  • 1,555
  • 3
  • 19
  • 44

2 Answers2

3

So, to paraphrase, you want to have a function that takes a Base object parameter, and uses that parameter as if it were actually a derived object.

So basically (psudocode):

void DoSomething (Base obj)
{
  obj.DoSomethingWithDerived();
}

In order to accomplish this, you need to do two things:

  1. Make Base polymorphic.
  2. Have your function take either a reference or a pointer to a Base -- not a Base by value.

Making Base Polymorphic.

A polymorphic class in C++ is any class that has at least 1 virtual method. In almost every case, you should have a virtual destructor anyway (for somewhat different reasons), so all you have to do here is:

class Base
{
public:
  virtual ~Base() {};
};

Reference or Pointer Parameter

If you construct a function that takes a Base by-value:

void DoSomething (Base obj)

...and then call it with a derived object:

int main()
{
  Derived der;
  DoSomething (der);
}

what ends up happening is a copy of der will be made in the call to DoSomething, but the copy won't be a complete copy -- it will only be a Base copy. All of the stuff that's specific to Derived will be sliced away.

So instead of taking a Base by-value, you have to take a Base either by-reference or by-pointer so that no copy is made:

void DoSomething (Base& obj);
Community
  • 1
  • 1
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • How do I then call a function on the Derived Class? – BlueSpud Jan 08 '14 at 21:10
  • 1
    By providing a virtual method in the base class and overriding it in the derived class. – John Dibling Jan 08 '14 at 21:33
  • Is there any other way? I want to have the derived class free to be whatever it wants to be. Ex. Store object-specific ints or functions. – BlueSpud Jan 08 '14 at 21:35
  • There's nothing stopping you from doing so; however, as far as this function is concerned the object is a Base, so the method you call (at least from this function) has to be known to the Base class. Your derived class can override that function to do whatever. – tabstop Jan 08 '14 at 21:39
  • @tabstop So theres absolutely no way to access the specific members of the derived class? – BlueSpud Jan 08 '14 at 21:42
  • I'm not quite clear whether you're wanting a "relay function" or not (the "DoSomething" in John's answer above is what I mean -- you're passing that object to that function). If so, the relay function must treat the object as a Base object. However, you can call member functions on that object from DoSomething, and those member functions can access all the specific members of the derived class that your heart desires (assuming you've set up the polymorphism as described above). – tabstop Jan 08 '14 at 21:47
  • @tabstop could I make a method that gives a pointer to the class so in that new method I could call that and get the derived class and use it as such? – BlueSpud Jan 08 '14 at 21:49
  • 1
    That's basically exactly what John described, but just to be clear I'm going to type up some example code in the big answer box rather than this little comment box and maybe it will be a little clearer? I hope. – tabstop Jan 08 '14 at 21:52
1

Let's see if this sample code enlightens.

#include <iostream>

class Base {
    public:
        int x;
        virtual void process() {std::cout << "Base: " << x << std::endl;}
};

class Derived : public Base {
    public:
        int y, z;
        virtual void process() {std::cout << "Base: " << x << " Derived: ";
            std::cout << y << " " << z << std::endl;
        }
};

void doSomething(Base& bob) {
    bob.process();
}

int main() {
    Derived foo;
    foo.x = 2;
    foo.y = 4;
    foo.z = 6;
    doSomething(foo);
    return 0;
}

In doSomething, bob is treated as a Base object (so there must be a process function in Base), but because the member function had been overridden in Derived, that definition takes over.

tabstop
  • 1,751
  • 11
  • 10