Home > Net >  Pointer not inheriting base class methods
Pointer not inheriting base class methods

Time:05-29

I just started learning polymorphism and am stuck with smth. I have a base class Object, and a derived class Ball. I would like to achieve polymorphism and use Ball methods on an Object pointer as such:

Object *ball = new Ball(P, dPdt, s, Forces);

cout << ball->getP() << " position\n" << ball->getdPdt() << " speed\n";

The first one, getP(), works fine because it's a method of the Object class and Ball's constructor calls Object's constructor to initialize it. Now, when it comes to getdPdt(), the compiles complains that no member named getdPdt in Object, which is obvious since I defined it in Ball. What am i doing/understanding wrong here ?

PS: I need by *ball to be an Object since this is for a physics simulation and everything must be an Object in order to simulate it. Later on, I guess I'll add a vector<unique_ptr<Object>> to keep track of

CodePudding user response:

If Object is a polymorphic type, a quick and dirty solution is to downcast.

Object *ball = new Ball(P, dPdt, s, Forces);
dynamic_cast<Ball*>(ball)->getdPdt();

This works only if you're sure that ball points to an Ball object. Otherwise, checks must be done before calling getdPdt on the casted pointer.


Note that the above solution goes against the goal of polymorphism that you wanted to achieve. Polymorphism is about providing a single interface (in this case the Object class) to entities of different types (in this case all of the subclasses of Object, including Ball). The interface should be designed such that all required operations are accessible through Object*.

Better polymorphic solution if defining getdPdt for Object makes sense:

class Object {
public:
  virtual int getdPdt() const {
    return 0;
  }
};

class Ball : public Object {
public:
  int getdPdt() const override {
    return 42;
  }
};

int main() {
  Object* obj = new Ball();
  // this returns 42, despite obj being `Object*`
  obj->getdPdt();
}

CodePudding user response:

C is a statically typed language. If the static type of an expression is Object, then it can do whatever an Object can do (and nothing else). If it's a Ball, then it can do whatever a Ball can do. You want it to be an Object but be able to do what Ball can do. You cannot have both, you need to decide one way or another.

Polymorphism is not about making properties that are exclusively defined for Ball magically available through an Object pointer. It is about Ball properties inherited from Object behave in a Ball-specific way.

Note that

Object *ball = new Ball(P, dPdt, s, Forces);
dynamic_cast<Ball*>(ball)->getdPdt();

can only be read this way:

 Object *ball = new Ball(P, dPdt, s, Forces); 
// I want to create a Ball but forget that it's a Ball
// I want to only remember that it's an Object

dynamic_cast<Ball*>(ball)->getdPdt();
// No! It's really a Ball after all! 
// My decision to forget it was wrong! I regret it!

Now anyone looking at these two lines of code would wonder whether you really know what you want, and rightfully so. Don't do things that you regret at the next line.

The situation is more complicated if these two lines are not next to each other. For example, you may have a vector of Object*:

std::vector<Object*> objects;
objects.push_back(new Ball(whatever));

// in a totally different function in a totally different file
dynamic_cast<Ball*>(objects[i])->getdPdt();

Now the questions that the astute reader would be asking are different, but no less difficult. Why is it known that objects[i] points to a Ball? Why isn't this knowledge encoded in the type of the variable? That's what types are for in C . Recall that C is a statically typed language. Any exception to this (and dynamic_cast is naturally an exception, what with it having the word "dynamic" in it) should be extremely well justified. If there is some code that decides what to do based on the type of the variable, that code should generally be a method in the base class.

In the end there are only two different things you can do while staying in the object-oriented design paradigm. Either add getdPdt to Object, so that it is available for all Objects; or put your Balls in a separate basket whose type says that there are Balls inside, and not just Objects. dynamic_cast is a deviation from the OO paradigm. Whether a deviation is acceptable to you is up to you to decide, but if you find yourself deviating from it a lot, then perhaps you want to consider a different paradigm.

  • Related