c++父类和子类的用法

C++ Parent and Child class usage

本文关键字:用法 子类 父类 c++      更新时间:2023-10-16

假设我有一个Person类。这个person类包含一个Shape

Shape父类有几个子类派生自它。例如RectangleCircle。每个子类都有自己的方法。例如Circle类有GetRadius(),而Rectangle类有GetWidth()和更多针对这种形状的方法。

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

我读了一些关于铸造的东西,但我发现它有点令人困惑,我不确定铸造是否会是最好的方式来做到这一点,或者是否有一个更efficiënt的方式去做这个完全。我该怎么做呢?

编辑1:编辑更多的澄清。我希望GetWidth()GetRadius()等方法返回不同的类型。

由于Shape超类至少有一个虚方法,您当然可以使用dynamic_cast来确定超类的每个实例是哪个子类。这当然是可能的,有时这样做是正确的,但大多数时候不是。

更确切地说,正确的做法是提前设计你的类,以一种方式,无论任何Shape可能完成的操作,都有一个Shape方法用于它,通常是虚拟的。最小的公分母是有一个由每个子类实现的纯虚方法,它返回特定子类所属的标识符。

但是,一般来说,如果您需要知道超类的实例的特定子类是什么,那么这是类层次结构设计不正确的线索。的确,生活并非总是100%完美的。有时,为了处理棘手的情况,可能有必要诉诸这种丑陋。但从一开始就不应该是这样。你应该尝试正确地设计你的类层次结构,这样就没有必要了。

即使是最小的公分母:

A)前面提到的返回超类所属特定子类的枚举标识符的函数,以及

B)超类定义了所有超类都可以实现的所有可能的虚方法,默认实现会抛出异常

可以在不涉及难看的强制类型转换的情况下做到这一点。

如果你有一个类型为Shape指针,它包含子类型的对象,如RectangleCircle,那么你可以使用dynamic_cast在运行时检查对象的类型。Dynamic_cast允许您安全地检查地址由指针保存的对象的运行时类型。

请查看https://en.wikipedia.org/wiki/Run-time_type_information#dynamic_cast查看如何完成此操作的示例。

您可以通过在Shape类上为适用于所有派生类的任何函数声明virtual函数来避免强制类型转换的需要。在本例中,您想知道每个派生类型是什么,这样您就可以有一个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;
}

示例输出

Foo with Circle
Bar with Rectangle
<<p> 生活例子/kbd>