2

I have a base type:

class Foo{
public:
int height;
int weight;

void jump();

}

I have a descendant:

class Bar : public Foo{
  //Has a different implementation of jump();
}

I have a factory that returns a kind of Foo;

static Foo createTheRightThing(int type){
  if (type == 0){
    return Foo();
  }
  else if (type ==1){
    return Bar();
  } 
}

The method that calls createTheRightThing looks like this:

void boo {
   Foo someFoo = FactoryClass::createTheRightThing(1); //Just using 1 to illustrate the problem.

}

The problem:

someFoo is always a Foo, and never a Bar, even when I pass 1 in. When I pass 1 in, I can see that the correct else block is entered, and the factory does indeed return a Bar. The member variables, match those set by the factory when creating the Bar. If I call someFoo.jump(), it is always the jump() in a Foo. It never calls the jump() in Bar.

What am I doing incorrectly ? How do I fix it ? I understand polymorphism in Java, Objective-c, but don't have much experience in C++. Is this problem because I am not creating a new object and returning a pointer ?

Rahul Iyer
  • 19,924
  • 21
  • 96
  • 190

2 Answers2

3

By returning the objects by value from the factory function, you're slicing them so that they'll always be the factory function's return type, which is Foo. For polymorphism to work, you need to return a pointer (reference would work too, but pointer is more appropriate in this case) to the object you create. You should change the factory function to

static std::unique_ptr<Foo> createTheRightThing(int type){
  if (type == 0){
    return std::unique_ptr<Foo>(new Foo());
  }
  else if (type ==1){
    return std::unique_ptr<Foo>(new Bar());
  } 

  // and maybe add this, or throw an exception
  return std::unique_ptr<Foo>();
}

In order for this to work correctly, you'll also need the following changes - Foo::jump should be virtual, as should the destructor of Foo

class Foo{
public:
  int height;
  int weight;

  virtual void jump();
  virtual ~Foo() = default;
};
Community
  • 1
  • 1
Praetorian
  • 106,671
  • 19
  • 240
  • 328
3
  1. You have slicing problem. What is object slicing?
  2. jump need to be virtual function for polymorphism. Which means you have to think about rule of three/five/zero. What is The Rule of Three? Rule-of-Three becomes Rule-of-Five with C++11?

So instead of returning Foo, you need to return a reference/pointer/smart poitner type.

class Foo{
public:
int height;
int weight;

virtual void jump();
virtual ~Foo() {}

}

class Bar : public Foo{
  //Has a different implementation of jump();
    void jump() override;
}

static std::shared_ptr<Foo> createTheRightThing(int type){ // better use enum type
  if (type == 0){ // better use switch case
    return std::make_shared<Foo>();
  }
  else if (type ==1){
    return std::make_shared<Bar>();
  } 
  // you need to return something here or have an assertion 
  // or (not recommended) throw exception
  return {}; // nullptr / std::shared_ptr<Foo>()
}
Community
  • 1
  • 1
Bryan Chen
  • 45,816
  • 18
  • 112
  • 143
  • 1
    I wouldn't return a shared pointer though. There is nothing in the problem that suggests shared ownership is required. – juanchopanza Jul 28 '14 at 06:41
  • shared pointer is just a quick solution that works for most of the cases. of cause unique pointer can be more optimal depends on the specific requirement. – Bryan Chen Jul 28 '14 at 07:23
  • without more details, you can't say this is wrong. but I agree unique pointer should be the default choice. and Praetorian already provide one so I won't change my answer. – Bryan Chen Jul 28 '14 at 07:28