结构成员的长列表

Posted

技术标签:

【中文标题】结构成员的长列表【英文标题】:Long list of struct members 【发布时间】:2021-08-18 17:40:57 【问题描述】:

我有一个有很多成员的结构。我决定为我的结构编写一些函数,但是将所有成员作为参数输入到函数调用中感觉不对。 有什么办法可以缩短吗?

items::items(std::string name_, std::string role_, uint16_t prize_, uint16_t phys_power_, uint16_t mag_power_,
             uint16_t attack_speed_, uint16_t life_steal_, uint16_t flat_pen_, uint16_t perc_pen_, uint16_t crit_,
             uint16_t phys_prot_, uint16_t mag_prot_, uint16_t cc_red_, uint16_t health_, uint16_t hp5_, uint16_t speed_,
             uint16_t cd_red_, uint16_t mana_, uint16_t mp5_) 
    name = name_;
    role = role_;
    prize = prize_;
    phys_power = phys_power_;
    mag_power = mag_power_;
    attack_speed = attack_speed_;
    life_steal = life_steal_;
    flat_pen = flat_pen_;
    perc_pen = perc_pen_;
    crit = crit_;
    phys_prot = phys_prot_;
    mag_prot = mag_prot_;
    cc_red = cc_red_;
    health = health_;
    hp5 = hp5_;
    speed = speed_;
    mana = mana_;
    mp5 = mp5_;


void items::print_item(items s) 
    std::cout << name << " " << role  << " " << prize << " " << phys_power << " " << mag_power << " " << attack_speed << " " << life_steal << " " << flat_pen <<
    " " << perc_pen << " " << crit << " " << phys_prot << " " << mag_prot << " " << cc_red << " " << health << " " << hp5 << " " << speed << " " << mana << " " <<
    mp5 << std::endl;    

【问题讨论】:

从使用初始化列表开始,移动复杂类型的语义和print_items 作为const 成员函数。但除此之外,不,C++ 标准中没有任何内容。您可能想查看 ECS 库而不是这样做。 聚合初始化,(如果可能/适当的话)可能会缩短这个时间。 【参考方案1】:

我们可以使用构建器模式解决您的问题。我们将有一个非常简单的 item 构造函数,它只将名称作为参数。我们将使用构建器模式构建其余属性。让我们从 ItemBuilder 和 Item 结构的前向声明开始。

struct ItemBuilder;

struct Item

  Item (std::string name_):name (name_)
  
  ;
  static ItemBuilder getBuilder(std::string name_);
  std::string name;
  std::string role;
  uint16_t prize;
  uint16_t phys_power;
  uint16_t mag_power;
  uint16_t attack_speed;
  uint16_t life_steal;
  uint16_t flat_pen;
  uint16_t perc_pen;
  uint16_t crit;
  uint16_t phys_prot;
  uint16_t mag_prot;
  uint16_t cc_red;
  uint16_t health;
  uint16_t hp5;
  uint16_t speed;
  uint16_t cd_red;
  uint16_t mana;
  uint16_t mp5;
;

现在让我们编写我们的 ItemBuilder。

struct ItemBuilder

private:
  Item m_item;
public:

  ItemBuilder (std::string name_):m_item (name_)
  
  

  operator  Item () const
  
    return std::move (m_item);
  ;

  ItemBuilder & role (std::string role_)
  
    m_item.role;
    return *this;
  ;
  ItemBuilder & prize (uint16_t prize_)
  
    m_item.prize = prize_;
    return *this;

  ;
  ItemBuilder & phys_pow (uint16_t phys_power_)
  
    m_item.phys_power = phys_power_;
    return *this;

  ;
  ItemBuilder & mag_power (uint16_t mag_power_)
  
    m_item.mag_power = mag_power_;
    return *this;

  ;
  ItemBuilder & attack_speed (uint16_t attack_speed_)
  
    m_item.attack_speed = attack_speed_;
    return *this;

  ;
  ItemBuilder & life_steal (uint16_t life_steal_)
  
    m_item.life_steal = life_steal_;
    return *this;
  ;
  ItemBuilder & flat_pen (uint16_t flat_pen_)
  
    m_item.flat_pen = flat_pen_;
    return *this;
  ;
;

最后别忘了Item::getBuilder

ItemBuilder 项目::getBuilder(std::string name_) 返回 ItemBuilder (name_);

int
main ()

  auto builder = Item::getBuilder("any");
  Item it = builder.role("mage").phys_pow(1).attack_speed(2).mag_power(100);
  std::cout << it.name << " " << it.phys_power << " " << it.attack_speed << " " << it.mag_power;
  return 0;

Run the code


有用的链接:

https://en.wikipedia.org/wiki/Builder_pattern#:~:text=The%20builder%20pattern%20is%20a,Gang%20of%20Four%20design%20patterns https://refactoring.guru/design-patterns/builder/cpp/example

【讨论】:

其他成员会怎样? @CKP 您将执行与属性角色和奖品完全相同的操作。为简单起见,我只使用了三个属性 @CKP 您想要关于 Godbolt 的完整解决方案吗? 我的代码中没有继承。我会尽快上传完整版。 @CKP 检查更新的答案,我还添加了一个链接,您可以在其中运行完整代码。我希望这能解决您的问题。【参考方案2】:

我假设这些是角色,或者,嗯,来自某种游戏的物品。我假设有有限数量的物品类型(法师、战士、矮人等),或者可能有一些物品“家族”,每个都有一些“子类型”。

编辑:第一步实际上是为成员设置合理的默认值,以便您只需要设置不同的值。在 C++11 及更高版本中,您可以简单地在成员声明中指定一个默认值,请参阅 https://en.cppreference.com/w/cpp/language/data_members,它可以与适当的构造函数结合使用。

准备值集的一种可能性是使用标准设置为每个“类型”定义一个常量原型。在使用适当的原型初始化之后,每个实例中只需要修改少数成员。

另一种可能性是将您的大型结构划分为可以单独设置的子结构:例如魔法能力、身体能力、当前状况等。这些可以组合起来创建基本项目,然后可以通过设置单个属性来定制它们。

分割成更小的子单元也可以通过继承层次结构来完成;但是复杂的继承已经失宠,因为它把代码耦合得太紧了。相反,composition 似乎导致代码更易于理解和维护(这不是几乎一样吗?)。但至少有几个接口可能是有序的,以便在适当的情况下对项目进行统一处理。

编辑:既然您在 cmets 中提到它:从文本文件构造项目是一个好主意。它使您无需重新编译即可创建多个不同的项目实例。我会推荐一个非常简单的 xml 结构,您可以手动或使用库 (TinyXML2?) 进行解析。或者,您也可以从更简单的逗号分隔列表开始(但可能仍然是键/值对,以便您可以省略一些并将它们保留为默认值!)您也可以在 Excel(或 LibreOffice 等)中创建、读取或编辑它。 )。

【讨论】:

确实,我尝试为 Smite 创建一个 ItemBuilder。我想编写可以例如的代码在游戏的某个阶段计算最省钱的构建或具有最高功率峰值的构建。自从我昨天开始编写代码以来,我只创建了结构并手动将每个项目及其属性(魔法/物理、冷却时间、力量等)键入到图表中。也许随后创建一个 ifstream 或某事。类似于从 excel 中读取数据,因此我可以创建一个包含所有项目的向量。如果你有更多的想法,请随时分享:)

以上是关于结构成员的长列表的主要内容,如果未能解决你的问题,请参考以下文章

c博客06-2019-结构体&文件

如何在 C++ 98 标准结构的初始化列表中初始化 tm struct 成员

go语言学习笔记 — 基础 — 高级数据类型 — 结构体:初始化结构体的成员变量

c语言中定义结构体都有哪些方法?

可以在不调用 memset 的情况下从构造函数初始化器列表中将成员结构设为零吗?

梦开始的地方 —— C语言结构体详解