【问题标题】: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?的可能重复

标签: c++ arrays class object vector


【解决方案1】:

您将需要某种间接方式。

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

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

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

【讨论】:

    【解决方案2】:

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

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

    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需要将它们视为选项;也许答案是因为没有理由!
    猜你喜欢
    • 2015-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-29
    • 1970-01-01
    • 2016-01-23
    • 2011-07-11
    相关资源
    最近更新 更多