Const彼此引用的对象

时间:2017-05-14 02:37:43

标签: c++

作为帮助可视化问题的动机(否则只是跳到下面的代码),假设我正在编写一个纸牌游戏,其中某些牌“在场”允许您“购买”手中的其他牌。所以,举个例子,假设你有一手说四张牌,其中包含一张王牌,你决定玩它。然后你得到另外一张四张牌,现在这张牌让你可以免费玩一张Queen卡。等等。

现在,我想编写这个游戏的代码。我创建了一个Card结构:

struct Card {
  std::string name_;

  Card(const std::string name) : name_{name} {}

  std::string name() const { return name; }
};

const Card ace("ace");
const Card one("one");
// etc.

但后来我决定不仅要记录一张牌的名字,还要记录它为免费提供的牌以及哪些牌免费提供这张牌。说这样的话:

struct Card {
  std::string name_;
  const Card* parent_; // card that gave this card for free
  const Card* child_;  // card that this card gives for free

  Card(const std::string name) : name_{name} {}

  std::string name() const { return name; }
  std::string parent() const { return parent_->name(); }
  std::string child() const { return child_->name(); }
};

(这段代码显然是零碎的而且不是很强大,但我只是希望得到原则。)为了添加父母/孩子,我还创建了以下方法:

struct Card {
  // ...

  private:
    void set_parent(const Card* c) {
      parent_ = c;
    }
  public:
    void add_child(Card& c) {
      child_ = &c;
      c.set_parent(this);
    }

  // ...
};

现在,我可以像这样创建Card个对象:

Card ace("ace");
Card queen("queen");
// etc.

ace.add_child(queen);
// etc.

但是,我不得不牺牲Card对象的常量。让我说清楚这只是一个基本的例子。我打算编写的代码在其Card类中有许多数据成员。因此,我想指向父/子卡而不明确复制数据。我也有很多“卡片”,所以我不希望重复尽可能多的数据。

我的问题是:我有什么方法可以将Card个对象保持为常量(因为它们从不包含可变数据)?或者我在考虑这个错误?

这个问题可能与隐含的问题有关:这甚至是重要的吗?我是否有很好的实际理由要求这个函数常量对象作为代码中的const?即使没有,那么即便如此,有没有办法让这些对象只是出于兴趣。

2 个答案:

答案 0 :(得分:1)

正如您所指出的,卡的数据(其身份加上一些关于它的规则)是不变的。而且,它们在编译时是已知的。所以:

#include <array>

enum class Rank {
    None, Ace, Two, Three, Four // ...
};

struct Card
{
    Rank rank = Rank::None;
    std::array<Rank, 2> from = {};
    std::array<Rank, 2> to = {};
};

constexpr Card cards[] = {
    {},
    {Rank::Ace, {Rank::Two, Rank::Three}, {}},
    {Rank::Two, {}, {Rank::Ace}},
    {Rank::Three, {Rank::Four}, {Rank::Ace, Rank::Four}},
    {Rank::Four, {Rank::Three}},
};

您可以根据需要调整阵列。现在您拥有一整套数据,这些数据在编译时都是已知的,并且存储紧凑。

答案 1 :(得分:0)

在不违反正确构造规则的情况下,您无法构造相互引用的const个对象。但是......

您可以静态构造它们为读写,privatestatic类成员,然后发布const引用。这将使这些成员的访问权限为只读。

sample.h

class Sample {
    const int priv_ro;  /* this is true const field */
    int       priv_rw;  /* this is read-write */
public:
    const int& pub_ro_ro; /* read only alias */
    const int& pub_rw_ro; /* idem */
    //int& pub_ro_rw; /* error, cannot alias a const as read write */
    int& pub_rw_rw; /* correct, public read write alias to private field */
    static Sample global_rw; /* static global variable (read-write) */
    static const Sample global_ro; /* static global variable (read-only) */
private:
    Sample(int ro, int rw):
        priv_ro(ro),
        priv_rw(rw),
        pub_ro_ro(this->priv_ro),
        pub_rw_ro(this->priv_rw),
        pub_rw_rw(this->priv_rw)
    {
        //priv_ro = ro; /* error, priv_ro is const */
        priv_rw = rw; /* ok */
    }
};

sample.cc

#include "sample.h"

Sample Sample::global_rw(8,3);
const Sample Sample::global_ro(5,2);

main.cc

#include <iostream>
#include "sample.h"

#define P(x) do{ std::cout << #x " = " << x << std::endl; } while(0)

int main()
{
    P(Sample::global_rw.pub_ro_ro);
    P(Sample::global_rw.pub_rw_ro);
    P(Sample::global_rw.pub_rw_rw);
    P(Sample::global_ro.pub_ro_ro);
    P(Sample::global_ro.pub_rw_ro);
    P(Sample::global_ro.pub_rw_rw);
    // Sample::global_ro.pub_ro_ro = 0; /* cannot assign. */
    // Sample::global_ro.pub_rw_ro = 0; /* cannot assign. */
    // Sample::global_ro.pub_rw_rw = 0; /* cannot assign. */
    // Sample::global_rw.pub_ro_ro = 0; /* cannot assign. */
    // Sample::global_rw.pub_rw_ro = 0; /* cannot assign. */
    Sample::global_rw.pub_rw_rw = 0;
    P(Sample::global_rw.pub_ro_ro);
    P(Sample::global_rw.pub_rw_ro);
    P(Sample::global_rw.pub_rw_rw);
    P(Sample::global_ro.pub_ro_ro);
    P(Sample::global_ro.pub_rw_ro);
    P(Sample::global_ro.pub_rw_rw);
}

生成文件

targets=sample

sample_objs=sample.o main.o
sample: $(sample_objs)
    $(CXX) $(LDFLAGS) -o $@ $(sample_objs)

如果取消注释注释行,您将看到不可访问的字段或const定义错误。