C++数据结构设计:具有不同领域和功能的儿童

C++ data structure design: children with different fields and function

本文关键字:功能 结构设计 数据 C++      更新时间:2023-10-16

我刚开始学习C++,我已经习惯了Java范式,所以我不确定应该如何做到这一点:我需要表示两种不同类型的产品向量:包装新鲜食品。它们有一些通用字段,只有一个实现(可用性、再库存数量等),但它们也有不同字段和函数和不同的返回类型。

I.E:新鲜食品可能有一个布尔字段需要冷藏,其他产品可以具有表示类别(食品、清洁、食品等)的整数,拼凑、通奸…)。

在Java中,我会创建一个具有公共字段的Product对象和一个PackagedProduct(扩展Product)加上一个具有特定字段的FreshProduct(也扩展Product)。然后,我会将每个乘积放在一个向量中,并在需要公共字段时作为乘积访问,在需要访问子字段时安全地(使用instanceof)投射到正确的类。我知道这在C++中不是正确的方式,我不想强迫java编程范式使用C++。

我可以想象:

  • 将所有cild所需的所有函数创建为父级中的虚拟函数,并在父级中添加一个表示cild类型的字段,这样就可以安全地强制执行
  • 创建一个包含两个不同向量的包装器对象,每个向量都是子对象的类型,并按正确的顺序返回值,最后使用第三个int向量

我认为这些解决方案真的很糟糕,我几乎可以肯定肯定肯定有更好的方法,但我无法想象。你能帮我吗?做这件事的正确方法是什么?

我需要代表两种不同类型的产品:包装食品和新鲜食品。

你真的需要同一向量中的两种类型的乘积吗?你不能有两个矢量吗?

std::vector<PackagedProduct> packaged;
std::vector<FreshProduct> fresh;
packaged.emplace_back(1, 2, 3);
fresh.emplace_back(4, 5, 6);

这将是迄今为止最有效的解决方案。(较少的间接寻址可以让预取器满意。)

如果您绝对需要同一矢量中的两种产品,则必须使用间接:

std::vector<std::unique_ptr<Product>> products;
products.push_back(std::make_unique<PackagedProduct>(1, 2, 3));
products.push_back(std::make_unique<FreshProduct>(4, 5, 6));

与其在运行时检查动态类型并向下转换,不如阅读虚拟方法。

基本思想与Java相同:使用继承创建类层次结构:

class Product { public: virtual ~Product(); ... };
class PackagedProduct : public Product { ... };
class FreshProduct : public Product { ... };

在Java中,向量(或列表、容器…)通过引用存储,而不是通过值存储。这就是关键的区别。在C++中,这意味着使用一个智能指针:

std::vector< std::shared_ptr< Product > > v;
v.push_back( std::make_shared< FreshProduct >( some args... ) );

一旦从矢量中检索到指针,就可以使用dynamic_pointer_cast来检查它是什么对象,但也可以使用其他选项。

当然,这只是一个粗略的想法,你需要了解很多关于细节、shared_ptr等的信息,但我希望你现在有足够的关键词和想法来搜索:)

创建一个具有公共字段的Product对象和一个PackagedProduct(扩展Product)加上一个具有特定字段的FreshProduct(也扩展Product)。然后将指向它们的智能指针存储在:中

std::vector<std::unique_ptr<Product> > Vec;

如果FredOverflow关于使用两个向量的建议不符合您的需求,则可以选择制作两种类型的变体,并保留一个变体向量。使用boost::variant可以很容易地做到这一点。您可以将所需的功能封装在自由函数中,也可以将变体封装在类中。这里有一个的例子

#include <boost/variant/variant.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
struct FreshProduct
{
  double price;
  bool needsRefrigeration;
};
struct PackagedProduct
{
  double price;
};
struct VariantProduct
{
  VariantProduct(const FreshProduct& p) : product(p) {}
  VariantProduct(const PackagedProduct& p) : product(p) {}
  double getPrice() const;
  bool needsRefrigeration() const
  {
    struct helper : public boost::static_visitor<bool>
    {
      bool operator ()(const FreshProduct& product) const
      {
        return product.needsRefrigeration;
      }
      bool operator ()(...) const
      {
        return false;
      }
    };
    return boost::apply_visitor(helper(), product);
  }
private:
  boost::variant<FreshProduct, PackagedProduct> product;
};
// in cpp
namespace {
  struct GetPrice : public boost::static_visitor<double>
  {
    template <class T>
    double operator ()(const T& product) const
    {
      return product.price;
    }
  };
} // anonymous namespace
double VariantProduct::getPrice() const
{
  return boost::apply_visitor(GetPrice(), product);
}

这种方法的优点是,您不需要使用动态分配来保持新鲜或包装产品的集合。缺点是,扩展变体中支持的类型不像使用继承那样容易。