如何在运行时决定将哪个派生类用作C++中的私有类成员

How can I decide at runtime which derived class to use as a private class member in C++?

本文关键字:C++ 成员 派生 运行时 决定      更新时间:2023-10-16

下面的问题对我来说有点难以表述,但请耐心等待,如果我能帮助澄清任何问题,请告诉我。

我正在为三维形状编写一个通用模拟。我正在使用一个基类:

class Shape{
    public:
    ...
        virtual double return_volume() =0;
    private:
        vector<double> coordinates;
    ...
};

现在,由于我不知道用户会选择什么形状,我从中派生了几个类。(例如:球体、立方体、四面体等)

到目前为止,一切都很好。主要的问题是我有一个Controller类,它启动并操作模拟。作为私人成员,它应该有多个形状的矢量(都是同一类型。例如:15个球体或10个立方体等)

class SimulationControl{
    public:
        void runsimulation();
    private:
        vector<Shape> all_shapes;
    ...
};

我想简单地用一个非默认构造函数初始化这个私有成员。现在,在我知道我做了什么之前,Eclipse已经告诉我"类型‘Shape’必须实现继承的纯虚拟方法‘Shape::return_volume’"

当然,我理解错误信息和我的错误,但我仍然不明白如何解决它

我希望能够做的是不定义向量的类型,然后在运行时通过具有正确派生类的构造函数简单地创建它,当我知道用户选择了哪种类型的模拟时。

有可能做到这一点吗?感谢

我不会赶时髦,建议在容器中使用指针,无论是聪明的还是愚蠢的。这是使用PIMPL习语的绝佳机会。

其思想是,类只是实际实现的包装器,并在对其进行调用时调用指向另一个对象的指针。包装器中包含的指针可以是多态的,这样它就可以实现它认为合适的函数。

class Shape{
    public:
        Shape() { pImpl = NULL; }
        Shape(const Shape& from) { pImpl = from.pImpl->clone(); }
        ~Shape() { delete pImpl; }
        Shape& operator=(const Shape& from) { pImpl = from.pImpl->clone(); }
    ...
        double return_volume() { return pImpl->return_volume(); }
    private:
        ShapeImpl * pImpl;
    ...
};
class ShapeImpl{
    public:
    ...
        virtual ShapeImpl* clone() const =0;
        virtual double return_volume() =0;
    private:
        vector<double> coordinates;
    ...
};

因为Shape类包含一个指针,所以您需要实现三规则并创建一个析构函数、复制构造函数和operator=。副本的默认值肯定会做错误的事情——它们只会复制指针值,而不会创建皮条对象的新副本。由于vector复制了这些函数周围的元素,因此这些函数肯定会被调用。

使用(智能)指针

您无法实例化抽象类,即使可以,也可能不是您想要的,因为您将无法创建这些形状的别名

您应该将SimulationControl类的定义更改为与此更相似的内容(假设您的形状在此共享所有权-如果SimulationControl是您的形状的唯一所有者,请使用unique_ptr而不是shared_ptr):

#include <memory>
class SimulationControl {
    public:
        void runsimulation();
    private:
        std::vector<std::shared_ptr<Shape>> all_shapes;
    ...
};

然后,您可以创建形状的实例,并将它们添加到all_shapes集合中,如下所示(假设MyShape是从Shape派生的一个具体的、默认的可构造类):

std::shared_ptr<MyShape> pShape = std::make_shared<MyShape>();
pShape->set_vertices(...); // I guess the class will have a member function
                           // that allows setting the shape's vertices...
all_shapes.push_back(pShape);

只能通过指针或引用进行多态性。尝试使用vector<Shape*>

既然你正在使用指针,你就必须为它们管理内存,但这是另一组问题。如果可以的话,试着使用智能指针,如果不能,请非常小心。如果您正在使用C++11,std::vector<std::unique_ptr<Shape>>可能适合您。