使用带有引用的对象向量的 C++ 语法

Posted

技术标签:

【中文标题】使用带有引用的对象向量的 C++ 语法【英文标题】:C++ syntax for using a vector of objects with references 【发布时间】:2015-01-29 00:25:46 【问题描述】:

我使用 C 已经有一段时间了,但我想在当前项目中使用 C++ 面向对象的样式,因为某些复杂性似乎更适合这种方法。所以,我是 C++ 最佳实践的新手,我希望有人能帮助我弄清楚如何做这个有希望的简单事情。

上周我阅读了这个网站和教程,学习了引用,将它们传递给函数,在另一个类中初始化静态类成员,以及其他一些我很高兴知道的东西,但我想我以初学者的水平了解每个人的基本想法,我很难理解如何将它们组合在一起。

这是我为测试我的概念理解而编写的思想实验程序。

在这里,我定义了一个“Button”类,其中包含一些当前微不足道的成员。

然后我定义了一个“Wand”类,从概念上讲,这是一种将按钮组织成一组按钮的方法。

编辑:根据 Steven 的有用回复,我更新了我的代码以尝试他建议的布局。这对我来说很有意义。我修正了一些我认为可能是拼写错误的小问题,但我认为 .back 有一些微妙之处,我做错了。我将 std::string 替换为“String”,因为它是 Arduino。

#include <vector>

class Button 
  private:
    bool _active;
    String _title;
    float _value;
  public:
    Button(String title, float value) : _title(title) , _value(value) 
    void setButton(bool active) 
      _active = active;
    ;
    String getTitle(void) 
      return _title;
    ;
    float getValue(void) 
      return _value;
    ;
    void setValue(float newvalue) 
       _value = newvalue;
    ;
;

class Wand 
  private:
    std::vector<Button> _Buttons;
    int _numButtons;
  public:
    Wand() ;
    Button& addButton(String title, float value) 
      _Buttons.push_back(Button(title, value));
      return _Buttons.back();
    
    Button& getButton(int number) 
      return _Buttons[number];
    ;
    int numButtons(void) 
      return _Buttons.size();
    ;
;

void setup() 
  // put your setup code here, to run once:
  SerialUSB.begin(9600);

  Wand wand = Wand();
  Button& OkButton = wand.addButton("Okay Button", 0);
  Button& NokayButton = wand.addButton("Nokay Button", 0);
  while(1) 
    SerialUSB.println(wand.getButton(0).getTitle() + "(via Wand): "+ wand.getButton(0).getValue());
    SerialUSB.println(OkButton.getTitle() + "(via Button): "+ OkButton.getValue());
    SerialUSB.println(wand.getButton(1).getTitle() + "(via Wand): "+ wand.getButton(1).getValue());
    SerialUSB.println(NokayButton.getTitle() + "(via Button): "+ NokayButton.getValue());

    OkButton.setValue(OkButton.getValue()+1);
    NokayButton.setValue(NokayButton.getValue()-1);
    delay(500);
  



void loop() 
  // put your main code here, to run repeatedly:


现在真正让我感到奇怪的是,尽管两个按钮的结构看似平行,但我从显示器得到的响应是这样的:

(via Wand): 0.00
(via Button): 15.00
(via Wand): -15.00
(via Button): -15.00
(via Wand): 0.00
(via Button): 16.00
(via Wand): -16.00
(via Button): -16.00

显然,我正确地更新和访问了第二个按钮,但第一个按钮似乎再次创建了该类的两个实例,魔杖中的一个没有被更新,而引用的版本是。

原帖:

现在,我已经阅读了有关 std::vector 的信息,这似乎是一种将动态分配的按钮数组存储在 Wand 内的自然方式。但是当我使用 Wand 的成员函数读取值时,很明显我没有使用最初分配的 Button 对象。

在这段代码中,我看到实际按钮的值发生了变化,但是通过 Button 向量请求时的值是不同的。我尝试添加一些 & 符号,但它大多只是导致编译器错误。

谁能告诉我如何正确地做这种事情?或者,如果这完全是错误的方法,提供如何以更标准的方式学习的链接?

#include <vector>

class Button 
  private:
    bool _active;
    char* _title;
    float _value;
  public:
    Button(char* title, float value) : _title(title) , _value(value) 
    void setButton(bool active) 
      _active = active;
    ;
    char* getTitle(void) 
      return _title;
    ;
    float getValue(void) 
      return _value;
    ;
    void setValue(float newvalue) 
       _value = newvalue;
    ;
;

class Wand 
  private:
    std::vector<Button> _Buttons;
    int _numButtons;
  public:
    Wand() ;
    void addButton(Button &newbutton) 
      _Buttons[_numButtons] = newbutton;
      _numButtons++;
    ;
    Button& getButton(int number) 
      return _Buttons[number];
    ;
    int numButtons(void) 
      return _numButtons;
    ;
;


void setup() 
  // put your setup code here, to run once:
  SerialUSB.begin(9600);

  Wand wand = Wand();
  Button OkButton = Button("Okay Button", 0);
  Button NokayButton = Button("Nokay Button", 0);
  wand.addButton(OkButton);
  wand.addButton(NokayButton);
  while(1) 
    SerialUSB.println(wand.getButton(0).getValue());
    SerialUSB.println(OkButton.getValue());
    OkButton.setValue(OkButton.getValue()+1);
    SerialUSB.println(wand.getButton(1).getValue());
    SerialUSB.println(NokayButton.getValue());
    NokayButton.setValue(NokayButton.getValue()-1);
    delay(500);
  



void loop() 
  // put your main code here, to run repeatedly:


【问题讨论】:

如果你有一个vector&lt;T&gt;,那是一个动态分配的T对象数组。这意味着如果存储阵列必须增长,则必须移动所有元素。您想要的是 vector&lt;unique_ptr&lt;T&gt;&gt; 或(不太可能)安放在 list&lt;T&gt; 中。 非常感谢!我会阅读这些内容,但如果这真的是微不足道的并且可以快速回答:我从我读到的内容中尝试了这个,这绝对是不正确的。我需要在哪些事情上使用 make_unique,以及如何传递 unique_ptr 引用的对象? Button OkButton = make_unique&lt;Button&gt;("Okay Button", 0); ? std::vector&lt;unique_ptr&lt;Button&gt;&gt; _Buttons;? wand.addButton(OkButton);? 这有点长。看看make_unique 返回什么。 很公平,感谢您抽出宝贵时间!我会阅读它,看看我是否可以自己解决。 @BrianNeltner - 您的Button 类使用指针,现在看起来还可以,但如果您需要使用new char[] 动态创建字符串,就会出现问题。解决这个问题的简单方法是使用std::string 而不是char* 来处理字符串数据。 【参考方案1】:

当您将按钮添加到魔杖时,您正在将副本添加到向量中,因此向量中的按钮地址与 OkButton 和 NoOkButton 的地址不同。

正如其他人指出的那样,使用 std::vector 可能是最强大的解决方案。但是,如果您真的想使用矢量

#include <vector>

class Button 
  private:
    bool _active;
    std::string _title;
    float _value;
  public:
    Button(std::string title, float value) : _title(title) , _value(value) 
    void setButton(bool active) 
      _active = active;
    ;
    std::string getTitle(void) 
      return _title;
    ;
    float getValue(void) 
      return _value;
    ;
    void setValue(float newvalue) 
       _value = newvalue;
    ;
;

class Wand 
  private:
    std::vector< Button > _Buttons;
  public:
    Wand() ;
    void addButton( std::string title, float value ) 
      _Buttons.push_back( Button( title, value ) );
    ;
    Button& getButton(int number) 
      return _Buttons[number];
    ;
    int numButtons(void) 
      return _Buttons.size();
    ;
;


void setup() 
  // put your setup code here, to run once:
  SerialUSB.begin(9600);

  Wand wand = Wand();
  wand.addButton("Okay Button", 0);
  wand.addButton("Nokay Button", 0);

  // If you add buttons after this, these references 
  // may be invalid.
  Button& OkButton = wand.getButton(0);
  Button& NokayButton = wand.getButton(1);

  while(1) 
    SerialUSB.println(wand.getButton(0).getValue());
    SerialUSB.println(OkButton.getValue());
    OkButton.setValue(OkButton.getValue()+1);
    SerialUSB.println(wand.getButton(1).getValue());
    SerialUSB.println(NokayButton.getValue());
    NokayButton.setValue(NokayButton.getValue()-1);
    delay(500);
  



void loop() 
  // put your main code here, to run repeatedly:


我还冒昧地演示了 stl 的一些其他功能。 std::string 通常比 char* 更方便,并且向量知道它们的大小,因此您无需显式跟踪按钮的数量。

【讨论】:

谢谢,这对我很有帮助,也很有意义。我肯定比我想要做的更喜欢这个设计。我编辑了我的帖子,提出了一些关于我在使用这种设计时看到的一些奇怪行为的进一步问题,我认为这与我不太了解的 .back 或 .push_back 的微妙之处有关。 我忘记了 std::vector 在添加元素时如果没有足够的空间可以移动内存。发生这种情况时,原始参考不再有效。我已将我的答案更新为应该可行的答案,但这仍然不是最佳解决方案。

以上是关于使用带有引用的对象向量的 C++ 语法的主要内容,如果未能解决你的问题,请参考以下文章

C++:对象、对对象的引用、对带有和不带有函数的向量元素的引用——观察到的性能差异

C++语法(指针和引用的区别)

C++,成员函数返回对包含指向 const 对象的指针的向量的 const 引用

C++ 向量初始化:使用这种语法到底发生了啥? [关闭]

我可以对带有变量的向量使用 C++11 列表初始化器语法吗?

在 C++ 中,如何获取指向向量的指针?