我正在尝试使一个类继承自其他类并覆盖一些方法。类'标题'是:
class Objeto {
public:
virtual bool interseca(const Rayo &rayo, float magnitud);
virtual bool breakNormal(const Punto &punto);
virtual Vector normal(const Punto &punto);
int idMaterial;
};
class Esfera: public Objeto {
public:
int idMaterial;
virtual bool interseca(const Rayo &rayo, float magnitud);
// etc
};
接下来在节目的其他地方(在Objeto和Esfera之外)我做:
// ObjectList is a Vector<Objeto>
Objeto o = esfera; /* Where esfera is a valid Esfera object */
ObjectList[0] = o;
ObjectList[0].interseca(rayo, magnitud);
我想要的是调用Esfera中的新版interseca
。通过这种方式,我可以添加更多对象(立方体,三角形等),并将它们视为通用的“Objetos”。
但是,除了interseca
的Esfera实施外,该计划还会调用Objeto::interseca
。
使用C ++执行此覆盖的正确方法是什么?这是覆盖的方式,我错过了什么,或者我是完全错的?任何提示或替代方法吗?
答案 0 :(得分:7)
如果通过指针或引用访问类,则只能获得多态行为。除此之外,在将派生类型复制到非指针/非引用基类型时,您正在切片对象。
切片:
http://en.wikipedia.org/wiki/Object_slicing
鉴于这些定义:
#include<iostream>
class Objeto {
public:
virtual bool interseca() {
return false;
}
};
class Esfera: public Objeto {
public:
int idMaterial;
virtual bool interseca() {
return true;
}
};
这不符合您的要求:
Esfera e;
Objeto o = e;
std::cout << o.interseca() << "\n";
假
但这会:
Esfera e;
Objeto& o = e;
std::cout << o.interseca() << "\n";
真
计划设计
将来可以用来避免这种情况的技术是使你的基类(纯)抽象。
你会在场景中实例化一个真实的Objeto
,还是只是定义一个基本类型?如果您只是定义基本类型(我建议使用),那么您可以interseca
,breakNormal
和normal
纯虚拟。然后,编译器将捕获类似您在此处的问题。
class Objeto {
public:
virtual bool interseca() = 0;
};
class Esfera: public Objeto {
public:
int idMaterial;
virtual bool interseca()
{
return true;
}
};
// ...
然后,这没关系:
Esfera e;
Objeto& o = e;
std::cout << o.interseca() << "\n";
汇编成功
但是这会导致编译器出错 - 这是一件好事,因为它正在捕捉一个错误:
Esfera e;
Objeto o = e;
std::cout << o.interseca() << "\n";
错误:无法分配抽象类型'Objeto'的对象
答案 1 :(得分:3)
你的覆盖是正确的,但似乎你还没有完全掌握C ++的对象模型。这个
Objeto o = esfera;
不符合您的想法。此 会将Objeto
esfera
子对象的副本 创建为o
。 (这称为“slicing”。)您想要的是使用参考引用 esfera
Objeto& o = esfera; // note the &
或o指针
Objeto* o = &esfera;
如果有疑问,请始终 更喜欢参考 。
答案 2 :(得分:2)
您已成功覆盖该方法。问题在于存储对象的方式以及在C ++中实现多态行为的方式。
要获得多态行为,必须使用指针或引用引用对象。 C ++不支持与Java或C#相同的引用类型语义。如果您有一个像这样创建的变量
Objeto o = esfera;
变量o
是基于对象Objeto
创建的(静态和动态)类型esfera
的新对象。这里发生的事情称为object slicing。
要获得多态行为,您必须使用指针或引用。例如,我们假设变量objeto
和esfera
属于Objeto
和Esfera
类型
分别
Objeto* op = &objeto;
op->interseca(rayo, magnitud); // virtual dispatch is used but since op points
// to an object of type Objeto Objeto::interseca
// gets called.
op = &esfera;
op->interseca(rayo, magnitud); // virtual dispatch is used and this time
// Esfera::interseca gets called.
您无法在一个vector
中存储不同类型的对象。如果您创建vector<Objeto>
并尝试在其中存储类型为Esfera
的对象,则会发生切片,就像变量o
的示例一样。
要拥有一个允许您获得多态行为的容器,您必须创建某种指针的vector
。这意味着你将不得不解决对象所有权的问题,矢量元素将引用。最好的解决方案很可能是使用一些智能指针的向量。
答案 3 :(得分:0)
您在堆栈上创建了一个Objeto。此项目始终具有Objeto类型。对于多态性,您必须使用引用或指针。