指针不继承基础 class 方法

Pointer not inheriting base class methods

我刚开始学习多态性,但被 smth 卡住了。我有一个基础 class Object 和一个派生 class Ball。我想实现多态性并在 Object 指针上使用 Ball 方法:

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

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

第一个 getP() 工作正常,因为它是 Object class 和 Ball 的构造函数调用 Object 的方法构造函数来初始化它。现在,当谈到 getdPdt() 时,编译会抱怨 Object 中没有名为 getdPdt 的成员,这很明显,因为我在 Ball。我 doing/understanding 哪里错了?

PS: 我需要 *ball 成为一个 Object 因为这是一个物理模拟,一切都必须是 Object 为了模拟它。稍后,我想我会添加一个 vector<unique_ptr<Object>> 来跟踪

如果 Object 是多态类型,一个快速而肮脏的解决方案是向下转型。

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

这只有在您确定 ball 指向一个 Ball 对象时才有效。否则,必须在对已转换的指针调用 getdPdt 之前进行检查。


请注意,上述解决方案违背了您想要实现的 多态性 目标。多态性是关于为不同类型的实体(在本例中是 [=12= 的所有子class,包括Ball)。界面的设计应使所有必需的操作都可以通过 Object*.

访问

如果为 Object 定义 getdPdt 有意义,则更好的多态解决方案:

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();
}

C++ 是一种静态类型语言。如果表达式的 static 类型是 Object,那么它可以做任何 Object 可以做的事情(除此之外别无他法)。如果它是 Ball,那么它可以做 Ball 可以做的任何事情。你希望它是一个 Object 但能够做 Ball 可以做的事情。你不能两者兼得,你需要选择一种方式。

多态性并不是让专门为 Ball 定义的属性通过 Object 指针神奇地可用。它是关于 BallObject 继承的属性以 Ball 特定的方式运行。

注意

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

只能这样读:

 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!

现在任何人看到这两行代码都会想知道你是否真的知道你想要什么,这是理所当然的。不要在下一行做你后悔的事情。

如果这两条线不相邻,情况就更复杂了。例如,您可能有一个向量 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();

现在,精明的 reader 会问的问题有所不同,但同样困难。为什么知道objects[i]指向一个Ball?为什么这些知识不以变量的类型编码?这就是 C++ 中的类型。回想一下,C++ 是一种静态类型语言。对此的任何例外(并且 dynamic_cast 自然是一个例外,其中包含“动态”一词)应该是非常合理的。如果有一些代码根据变量的类型决定做什么,那么该代码通常应该是基类 class.

中的一个方法。

最后,在 object-oriented 设计范例中,您只能做两件不同的事情。要么将 getdPdt 添加到 Object,以便它可用于所有 Object;或者将您的 Ball 放在一个单独的篮子中,篮子的类型表明里面有 Ball,而不仅仅是 Objectdynamic_cast 是对 OO 范式的偏离。一个偏差是否可以接受由你决定,但如果你发现自己偏离它很多,那么也许你想考虑一个不同的范例。