说我有一个Person
课程。此人类持有Shape
。
Shape
父类有几个派生自它的子类。例如Rectangle
和Circle
。这些子类中的每一个都有自己的方法。例如,Circle类具有GetRadius()
,而Rectangle类具有GetWidth()
以及更多特定于该类形状的方法。
现在假设我有几个人,其中一些持有矩形,另一些持有圈子。我想知道每个人持有什么样的形状,我想从这些形状中获取信息。但是我不能这样做,因为Person持有一个Shape,所以它不能访问任何特定于子的方法。
我读了一些关于铸造的东西,但我发现它有点令人困惑,我不确定铸造是否是最好的方法,或者是否有更有效的方法完全解决这个问题。那我怎么能这样做呢?
编辑1:编辑以获得更多说明。
我希望GetWidth()
和GetRadius()
等方法返回不同的类型。
答案 0 :(得分:0)
如果你有Shape
类型的指针,它包含Rectangle
或Circle
等子类型的对象,那么你可以使用{{1在运行时检查对象的类型。 dynamic_cast将允许您安全地检查其地址由指针持有的对象的运行时类型。
请查看https://en.wikipedia.org/wiki/Run-time_type_information#dynamic_cast以获取如何完成此操作的示例。
答案 1 :(得分:0)
如果dynamic_cast
超类具有至少一个虚方法,您当然可以使用Shape
来确定超类的每个实例的子类。这当然是可能的,有时这是正确的做法,但大部分时间都没有。
相反,正确的做法是提前设计你的类,以便任何操作都可以使用dynamic_cast
任何Shape
方法完成,通常是虚拟的Shape
方法。最小的共同点是拥有一个由每个子类实现的纯虚方法,它返回一个特定子类的标识符。
但是,通常,如果您需要知道超类的实例是什么特定的子类,那么它就是一个线索,即类层次结构设计不正确。确实,生活并非始终完美无缺。为了处理棘手的情况,有时可能需要诉诸这种丑陋。但这不应该是从一开始的计划。您应该尝试正确设计类层次结构,这是不必要的。
即使是最低的共同点:
A)上述函数返回一些枚举标识符,超类的特定子类是
B)定义所有超类可以实现的所有可能虚拟方法的超类,使用抛出异常的默认实现
可以以不涉及难看的演员阵容的方式做到这一点。
答案 2 :(得分:0)
通过在tree
类上声明适用于所有派生类的任何函数的virtual
函数,可以避免进行强制转换。在这种情况下,您想知道每个派生类型是什么,因此您可以拥有Shape
函数。你不必完全按照这种方式去做,但以下是你如何做到这一点的一个例子。
getType()
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Shape
{
public:
virtual ~Shape() {}
virtual Shape* clone() const = 0;
virtual std::string getType() const = 0;
};
class Circle : public Shape
{
public:
virtual Circle* clone() const override { return new Circle(*this); }
virtual std::string getType() const override { return "Circle"; }
};
class Rectangle : public Shape
{
public:
virtual Rectangle* clone() const override { return new Rectangle(*this); }
virtual std::string getType() const override { return "Rectangle"; }
};
class Person
{
public:
explicit Person(const std::string& name, const Shape& shape) :
mName(name),
mShape(shape.clone())
{
}
std::string mName;
std::unique_ptr<Shape> mShape;
};
int main()
{
std::vector<Person> people;
people.emplace_back("Foo", Circle());
people.emplace_back("Bar", Rectangle());
for (const auto& person : people)
{
std::cout << person.mName << " with " << person.mShape->getType() << "\n";
}
return 0;
}