未继承基类方法的指针



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

Object *ball = new Ball(P, dPdt, s, Forces);
cout << ball->getP() << " positionn" << ball->getdPdt() << " speedn";

第一个,getP(),工作得很好,因为它是Object类的方法,Ball的构造函数调用Object的构造函数来初始化它。现在,当谈到getdPdt()时,编译器抱怨Object中没有名为getdPdt的成员,这是显而易见的,因为我在Ball中定义了它。我在这里做错了什么/理解错了什么?

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

c++是一种静态类型语言。如果表达式的静态类型是Object,那么它可以做Object可以做的任何事情(没有其他)。如果它是Ball,那么它可以做Ball能做的任何事情。您希望它是Object,但能够做Ball可以做的事情。你不能两者兼得,你必须做出选择。

多态性并不是让专门为Ball定义的属性通过Object指针神奇地可用。它是关于Ball属性继承自Object的行为在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();

现在,机敏的读者会问的问题是不同的,但同样困难。为什么知道objects[i]指向Ball?为什么这些知识没有被编码到变量的类型中?这就是c++中类型的作用。回想一下,c++是一种静态类型语言。任何例外(dynamic_cast自然是例外,因为它有"动态"这个词;它应该是非常合理的。如果有一些代码根据变量的类型决定要做什么,那么这些代码通常应该是基类中的一个方法。

最后,在保持面向对象设计范式时,您只能做两件不同的事情。或者将getdPdt添加到Object,以便所有Object都可用;或者把你的Ball放在一个单独的篮子里,这个篮子的类型表明里面有Ball,而不仅仅是Objectdynamic_cast偏离了OO范式。一种偏差是否可以被你接受取决于你自己,但是如果你发现自己经常偏离它,那么也许你需要考虑一个不同的范式。

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

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

此操作仅在您确定ball指向Ball对象时才有效。否则,必须在对强制转换的指针调用getdPdt之前进行检查。


注意,上面的解决方案违背了您想要实现的多态性的目标。多态性是指为不同类型的实体(在本例中为Object类)提供单个接口(在本例中为Object的所有子类,包括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();
}

相关内容

  • 没有找到相关文章

最新更新