C ++父类和子类的使用

时间:2016-07-04 21:55:43

标签: c++

说我有一个Person课程。此人类持有Shape

Shape父类有几个派生自它的子类。例如RectangleCircle。这些子类中的每一个都有自己的方法。例如,Circle类具有GetRadius(),而Rectangle类具有GetWidth()以及更多特定于该类形状的方法。

现在假设我有几个人,其中一些持有矩形,另一些持有圈子。我想知道每个人持有什么样的形状,我想从这些形状中获取信息。但是我不能这样做,因为Person持有一个Shape,所以它不能访问任何特定于子的方法。

我读了一些关于铸造的东西,但我发现它有点令人困惑,我不确定铸造是否是最好的方法,或者是否有更有效的方法完全解决这个问题。那我怎么能这样做呢?

编辑1:编辑以获得更多说明。 我希望GetWidth()GetRadius()等方法返回不同的类型。

3 个答案:

答案 0 :(得分:0)

如果你有Shape类型的指针,它包含RectangleCircle等子类型的对象,那么你可以使用{{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;
}

Live Example