【问题标题】:How to let a variable be dependent on other variables inside a class?如何让一个变量依赖于类中的其他变量?
【发布时间】:2020-03-12 10:24:28
【问题描述】:

变量international_standard_book_number 有什么问题?每当isbn_field_i 发生变化时,我怎样才能让它发生变化?

#include <iostream>
#include <string>

class ISBN
{
private:
  unsigned int isbn_field_1 = 0;
  unsigned int isbn_field_2 = 0;
  unsigned int isbn_field_3 = 0;
  char digit_or_letter = 'a';
  std::string international_standard_book_number =
    std::to_string(isbn_field_1) + "-" + std::to_string(isbn_field_2) + "-" +
    std::to_string(isbn_field_3) + "-" + digit_or_letter;

public:
  ISBN()
  {
    isbn_field_1 = 0, isbn_field_2 = 0, isbn_field_3 = 0, digit_or_letter = 'a';
  }
  ISBN(unsigned int a, unsigned int b, unsigned int c, char d)
  {
    isbn_field_1 = a, isbn_field_2 = b, isbn_field_3 = c, digit_or_letter = d;
  }
  friend std::ostream& operator<<(std::ostream& os, ISBN const& i)
  {
    return os << i.international_standard_book_number;
  }
};

int
main()
{
  ISBN test(1, 2, 3, 'b');
  std::cout << test << "\n";
  return 0;
}

输出:

0-0-0-a

期望的输出:

1-2-3-b

编辑:This question 的目的不是我的(为什么,而不是如何),它的答案对我的帮助不如这个主题的答案。

【问题讨论】:

标签: c++ c++17 initialization-list default-initialization


【解决方案1】:

变量international_standard_book_number 有什么问题?每当isbn_field_i 发生变化时,我怎样才能让它发生变化?

一般来说:每次一个组件发生变化时,您都必须重新分配它。

在您的特定情况下:使用初始化列表更改构造函数。

我的意思是……而不是

ISBN(unsigned int a, unsigned int b, unsigned int c, char d)
 {isbn_field_1=a, isbn_field_2=b, isbn_field_3=c, digit_or_letter=d;};

ISBN(unsigned int a, unsigned int b, unsigned int c, char d)
 : isbn_field_1{a}, isbn_field_2{b}, isbn_field_3{c}, digit_or_letter{d}
{}

现在你的示例代码编写

1-2-3-b

有什么变化?

ISBN(unsigned int a, unsigned int b, unsigned int c, char d)
 {isbn_field_1=a, isbn_field_2=b, isbn_field_3=c, digit_or_letter=d;};

首先你的字段是默认初始化的,所以

isbn_field_1    = 0;
isbn_field_2    = 0;
isbn_field_3    = 0;
digit_or_letter = 'a';

international_standard_book_number="0"+"-"+"0"+"-"+"0"+"-"+'a';

然后执行构造函数的主体

isbn_field_1    = 1;
isbn_field_2    = 2;
isbn_field_3    = 3;
digit_or_letter = 'b';

international_standard_book_number 保持不变。

ISBN(unsigned int a, unsigned int b, unsigned int c, char d)
 : isbn_field_1{a}, isbn_field_2{b}, isbn_field_3{c}, digit_or_letter{d}
{}

初始化列表初始化字段(并替换默认初始化)

isbn_field_1    = 1;
isbn_field_2    = 2;
isbn_field_3    = 3;
digit_or_letter = 'b';

然后执行international_standard_book_number的默认初始化但使用新值,所以

international_standard_book_number="1"+"-"+"2"+"-"+"3"+"-"+'b';

【讨论】:

  • “:”之后和构造函数主体之前的所有内容都是初始化列表吗?或者它也可以是别的东西?
  • @SAJW - 好吧......在:之后和构造函数的主体之前(其中的每个初始化都是)初始化列表或(我不知道是否可以调用它初始化器列表,在这种情况下)对委托构造函数的调用(参见 Ayxan 答案中的示例)。
【解决方案2】:

使用成员函数。

#include <iostream>
#include <string>

class ISBN
{
private:
    unsigned int isbn_field_1=0;
    unsigned int isbn_field_2=0;
    unsigned int isbn_field_3=0;
    char digit_or_letter='a';
    std::string international_standard_book_number() const {
        return std::to_string(isbn_field_1)+"-"+std::to_string(isbn_field_2)+"-"+std::to_string(isbn_field_3)+"-"+digit_or_letter;
    }
public:
    ISBN(){isbn_field_1=0, isbn_field_2=0, isbn_field_3=0, digit_or_letter='a';}
    ISBN(unsigned int a, unsigned int b, unsigned int c, char d){isbn_field_1=a, isbn_field_2=b, isbn_field_3=c, digit_or_letter=d;};
    friend std::ostream &operator<<(std::ostream &os, ISBN const &i) 
    { 
        return os << i.international_standard_book_number();
    }
};


int main()
{
    ISBN test(1,2,3,'b');
    std::cout << test << "\n";
    return 0;
}

c++ 中的变量使用值语义。当你这样做时

std::string international_standard_book_number=
std::to_string(isbn_field_1)+"-"+std::to_string(isbn_field_2)+"-"+std::to_string(isbn_field_3)+"-"+digit_or_letter;

它将根据isbn_field_n 现在拥有的值为international_standard_book_number 分配一个值。它不会在这些变量之间创建某种自动链接,以确保它们保持同步。

如果您想要这种行为,则必须确保每次更新其他字段时都更新 international_standard_book_number

【讨论】:

  • 我认为这并不能真正回答问题,OP 希望从类中的其他成员初始化一个字符串成员。当然,您可以使用成员函数,但这是不同的设计。您也可以在构造函数中分配字符串值,但我相信 OP 想知道为什么发布的代码不能按预期工作。
  • @jdehesa OP 询问“我怎样才能让它改变,每当 isbn_field_i 改变时?”,不仅在初始化之后,应该使用成员函数。
  • @idclev463035818 再读一遍,确实可以这样理解,我不确定这个问题是指“每当构造函数的参数发生变化”还是“每当成员的值发生变化”构造对象的变量发生变化”。
  • @jdehesa 问题只是陈述了变量国际标准书号有什么问题?。查看 OP 代码,他似乎希望对 isbn_field_n 的更改传播到 international_standard_book_number,这是使用成员函数最容易获得的行为。
  • @super 是的,但成员变量是私有的,不能更改,所以对象实际上是不可变的......无论如何,现在有涵盖不同解释的答案我认为所以 OP 可能会找到什么他们需要。
【解决方案3】:

如果您只需要设置一次值(例如,其他值在对象之后不会改变 被构造)你可以使用一个初始化列表:

ISBN(unsigned int a, unsigned int b, unsigned int c, char d) 
    : isbn_field_1(a), 
      isbn_field_2(b),
      isbn_field_3(c),
      digit_or_letter(d),
      international_standard_book_number(
          std::to_string(isbn_field_1) + "-" + 
          std::to_string(isbn_field_2) + "-" + 
          std::to_string(isbn_field_3) + "-" + 
          digit_or_letter)
{};

但请记住,成员仍然按照声明的顺序进行初始化,而不是按照初始化列表的顺序。

从技术上讲,您不需要在初始化列表中初始化 international_standard_book_number,正如 max66 的回答所示,这是个人喜好问题。

【讨论】:

    【解决方案4】:

    维护类不变量(取决于变量)这是您必须手动编码的内容。这是我们需要课程的原因之一。在一个类中,您可以禁止直接更改成员(将它们设为私有),但是当它们通过例如特殊的 set 方法更改时相应地更新不变量。

    例如

    void set_field_1(int field) {
      isbn_field_1 = field;
      international_standard_book_number = std::to_string(isbn_field_1)+"-"+std::to_string(isbn_field_2)+"-"+std::to_string(isbn_field_3)+"-"+digit_or_letter; 
    }
    

    【讨论】:

      【解决方案5】:

      我想添加到@max66's answer

      通常你有一个相互调用的构造函数的层次结构和一个最终的最终“主”构造函数,它接受所有参数并初始化变量。这避免了代码重复并极大地简化了哪些构造函数初始化了什么。您可以在下面的示例中看到我的意思。除此之外,要以可读的方式进行正确的字符串格式化,请使用{fmt} 库:

      #include <fmt/format.h>
      #include <string>
      
      class ISBN
      {
      private:
              unsigned int isbn_field_1;
              unsigned int isbn_field_2;
              unsigned int isbn_field_3;
              char digit_or_letter;
              std::string international_standard_book_number;
      
      public:
              ISBN()
                      : ISBN{ 0, 0, 0, 'a' }
              {}
              ISBN(unsigned int a, unsigned int b, unsigned int c, char d)
                      : isbn_field_1{ a }
                      , isbn_field_2{ b }
                      , isbn_field_3{ c }
                      , digit_or_letter{ d }
                      , international_standard_book_number{ fmt::format("{}-{}-{}-{}",
                                                                        isbn_field_1,
                                                                        isbn_field_2,
                                                                        isbn_field_3,
                                                                        digit_or_letter) }
              {}
      };
      

      【讨论】:

      • 啊,所以变量应该只声明而不是设置,而是默认构造函数设置默认值。是对的吗?也感谢您提及 {fmt}!
      【解决方案6】:

      Visual Studio 2019 中的这段代码至少可以工作:

      #include <iostream>
      #include <string>
      
      class ISBN
      {
      private:
          unsigned int isbn_field_1 = 0;
          unsigned int isbn_field_2 = 0;
          unsigned int isbn_field_3 = 0;
          char digit_or_letter = 'a';
          std::string international_standard_book_number =
              std::to_string(isbn_field_1) + "-" + std::to_string(isbn_field_2) + "-" +
              std::to_string(isbn_field_3) + "-" + digit_or_letter;
      
      public:
          ISBN(unsigned int a, unsigned int b, unsigned int c, char d)
              :isbn_field_1(a), isbn_field_2(b), isbn_field_3(c), digit_or_letter(d), international_standard_book_number(std::to_string(isbn_field_1) + "-" + std::to_string(isbn_field_2) + "-" +
                  std::to_string(isbn_field_3) + "-" + digit_or_letter)
          {
          }
          friend std::ostream& operator<<(std::ostream& os, ISBN const& i)
          {
              return os << i.international_standard_book_number;
          }
      };
      
      int
      main()
      {
          ISBN test(1, 2, 3, 'b');
          std::cout << test << "\n";
          test = {2, 3, 4, 'c'};
          std::cout << test << "\n";
          return 0;
      }
      

      另外,为什么是空的构造函数?

      【讨论】:

        猜你喜欢
        • 2021-02-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-25
        • 2015-03-19
        相关资源
        最近更新 更多