1

I have a Base class, and a Derived class of Base

struct Base{};
struct Derived: public Base{};

I want to make a function that accepts Base*, but has different functionality when passed a Derived*.

void myFunc(Base* base){
 std::cout << "myFunc(base)" << std::endl; 
}

void myFunc(Derived* derived){
 std::cout << "myFunc(derived)" << std::endl;
}

My problem is when I try to use polymorphism, the function doesn't behave as desired because I'm always passing Base*'s.

Base* base = new Base();
Base* derived = new Derived();

myFunc(base);
myFunc(derived);

Outputs:

myFunc(base)
myFunc(base)

Desired outputs:

myFunc(base)
myFunc(derived)

The reason I can't use casting like - (Derived*)derived - is because I'm using an array of Base*

#include <iostream>

struct Base{};    
struct Derived: public Base{};

void myFunc(Base* base){
 std::cout << "myFunc(base)" << std::endl; 
}

void myFunc(Derived* derived){
 std::cout << "myFunc(derived)" << std::endl;
}

void myFunc(Base** bases, size_t count){
 for(auto i = 0; i < count; i++){
  myFunc(bases[i]);
 }
}

int main(){
 Base* bases[2];
 bases[0] = new Base();
 bases[1] = new Derived();

 myFunc(bases, 2);
}

The reason I can't make myFunc a virtual member function of base, is because I want to encapsulate myFunc's functionality in a separate class to avoid a monolithic base class.

#include <iostream>

struct Base{};

struct Derived: public Base{};

struct DoesStuff{
 void doStuff(Base* base){
  std::cout << "doStuff(base)" << std::endl; 
 }

 void doStuff(Derived* derived){
  std::cout << "doStuff(derived)" << std::endl;
 }

 void doStuff(Base** bases, size_t count){
  for(auto i = 0; i < count; i++){
   doStuff(bases[i]);
  }
 }
};

struct DoesOtherStuff{
 void doOtherStuff(Base* base){
  std::cout << "doOtherStuff(base)" << std::endl; 
 }

 void doOtherStuff(Derived* derived){
  std::cout << "doOtherStuff(derived)" << std::endl;
 }

 void doOtherStuff(Base** bases, size_t count){
  for(auto i = 0; i < count; i++){
   doOtherStuff(bases[i]);
  }
 }
};

int main(){
 Base* bases[2];
 bases[0] = new Base();
 bases[1] = new Derived();

 DoesStuff stuffDoer;
 DoesOtherStuff otherStuffDoer;

 stuffDoer.doStuff(bases, 2);
 otherStuffDoer.doOtherStuff(bases, 2);
}

How do I get myFunc to know a Base* is secretly a Derived*. I think I could use typeid, but I'm not sure that's the most appropriate solution. Correct me if I'm wrong.

10
  • 2
    you have to declare your functions as virtual. Keep in mind its better to pass a reference than a pointer Commented Nov 9, 2015 at 22:49
  • Try using a template and provide the appropriate specializations, instead of introducing ambiguity via Base* and Derived* pointer types. Commented Nov 9, 2015 at 22:49
  • 1
    @KostasRim There's no surrounding class for the functions in question. How should these be virtual actually? Commented Nov 9, 2015 at 22:50
  • A case for dynamic_cast? Commented Nov 9, 2015 at 22:51
  • 3
    A case for a redesign before dynamic_cast, any day Commented Nov 9, 2015 at 22:56

1 Answer 1

1

In order to get this to work via polymorphism is to do the following:

  1. Create a virtual member function in the Base class that does what you want to do for Base classes.

  2. Override that member function in the Derived class and have it do what you want for Derived classes.

That's the essence of polymorphism. The reason it doesn't work for your non-member or free function is because they are both passed Base class pointers.

Sign up to request clarification or add additional context in comments.

5 Comments

Let's add it's only the essence of runtime (aka. dynamic) polymorphism. The overloads or template routes are also polymorphism, but not classical OOP polymorphism (I'd argue that the classic OOP style should be rare in C++, because typically other languages are more suited to that...)
That's fair. But I don't agree with the very last part of your statement that is contained in parentheses.
What if myFunc is part of a class I have responsible for doing something to Base and Derived. Right now I'm avoiding a problem of having dozens of unrelated functions inside of Base, and instead having classes that operate on arrays of Base
@WillyGoat This sounds like a classic double-dispatch issue, where you want to separate the representation of the objects from the algorithms that run on them. That's exactly what the visitor pattern is for: en.wikipedia.org/wiki/Visitor_pattern
@ChrisHayden Interesting. I'm reading into it right now, thank you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.