通用对象向量/数组,其中每个存储的对象都有不同的类

Posted

技术标签:

【中文标题】通用对象向量/数组,其中每个存储的对象都有不同的类【英文标题】:Generic object vector/array, where each stored object has a different class 【发布时间】:2017-10-27 13:54:53 【问题描述】:

有什么方法可以制作通用对象向量或数组,让我可以将不同类的对象保存在单个向量或数组中。

我基本上想知道我是否可以切换出调用了哪个版本的类。

即类 square 被类 circle 替换,但两者都有一个名为 findArea 的函数,因此在调用该对象向量/数组时主函数不会中断。

【问题讨论】:

如果您只想使用通用功能,哪些不能存储指向基类的指针 (std::unique_ptr)? 定义“不同的类”。完全不相关,还是只是共同基础的不同类?看,由于含糊不清,您已经引出了两个完全不同的答案,其中大概只有一个实际上适用于您。如果是后者,那就简单研究基础多态性;我们不需要解释虚函数。 如果是前者,那么:How can I store objects of differing types in a C++ container?的可能重复 【参考方案1】:

您将需要某种间接方式。

std::vector<std::unique_ptr<Shape>> array_of_shapes;

所有形状都是 Shape 派生的类。

如果 Shape 有一个virtual findArea(),那么您可以随时调用array_of_shapes[i]-&gt;findArea();(假设该位置实际上已被填充)。

【讨论】:

【参考方案2】:

您正在寻找的是多态性。这是 C++ 和其他面向对象语言的基本特性。

您可以声明一个名为 Shape 的基类,并从中继承您的 SquareRound 类。然后,只需在您选择的标准库容器中保存指向它的指针(或更好的智能指针)。

struct Shape 
    virtual size_t getArea() = 0;
;

struct Round : public Shape 
    virtual size_t getArea()  /* return calc */ 
;

struct Square : public Shape 
    virtual size_t getArea()  /* return calc */ 
;

main () 
    auto round = std::static_pointer_cast<Shape>(std::make_shared<Round>());
    auto square = std::static_pointer_cast<Shape>(std::make_shared<Square>());

    std::vector<std::shared_ptr<Shape>> vec;
    vec.push_back(round);
    vec.push_back(square);

    for (auto & x : vec)
        cout << x->getArea() << endl;


关于您的评论:

我基本上想知道是否可以切换出调用了哪些版本的类。

您可以使用以下方法之一来实现:

RTTI:使用dynamic_cast&lt;&gt;检查你持有的对象是否属于某种类型:

if (dynamic_cast<Round>(x.get()) != NULL)
    // x is a Round
else if (dynamic_cast<Square>(x.get()) != NULL)
    // x is a Square

在你的类中添加一个成员,根据类型对其进行初始化,然后简单地检查一下:

struct Shape 
    enum Type 
         Round,
         Square
    

    Type _type;
    Type getType()  return _type; 

    Shape(Type type) : _type(type) 
    [..]


struct Round : public Shape 
    Round() : Shape(Shape::Round) 
    [..]
;

// Check it later on using:
switch (x->getType()) 
case Round:
    // use
    break;
[..]

使用typeid()。只要你的基类是多态的,它就会给你正确的类型信息:

if (typeid(*x) == typeid(Round)) 
    // x is a Round
 else if (typeid(*x) == typeid(Square)) 
    // x is a Square

【讨论】:

如果你问我,if/switch on RTTI 或一些自定义类型信息值永远不是答案。关于虚函数的答案的第一部分就足够了;其余的,对我来说,很可能只会让那些还不了解多态性的用户混淆编写糟糕的代码。 @underscore_d,您能详细说明一下吗? 虚拟函数已经根据派生类的具体类型实现了不同行为的需求,同时在基类中保留了一个通用接口。忽略该语言非常有用的功能,而是使用条件来实现您自己的子类特定行为是没有意义的、丑陋的、难以维护的,并且需要基础知道其子类的细节,所以这是一种代码臭味。此外,您没有解释为什么当虚函数存在时OP需要将它们视为选项;也许答案是因为没有理由!

以上是关于通用对象向量/数组,其中每个存储的对象都有不同的类的主要内容,如果未能解决你的问题,请参考以下文章

C++如何创建异构容器

如何找到存储在 C++ 向量中的对象的类方法?

引用对象的良好做法

将对象的类类型保存到文件并在 C++ 中读回

无法拼接对象数组中的项目

将不同大小的数组组合成一个对象?