C++ 将 class 传递给构造函数 = 不传递相同的实例?

C++ passing class to constructor = not passing same instance?

似乎,当我传递 class 时,它并没有像我期望的那样传递 class 的持久(相同)实例。我假设这与内存状态有关,但如果有人能准确解释正在发生的事情,我将不胜感激。这个问题很容易证明如下:

Main.ino

#include "Debug.h"
#include "Box.h"

Debug debug;
Box box(debug);

void loop(){
  debug.message("loop");
  debug.line();
}

void setup(){
  debug.init();
  box.init();
  debug.message("Setup Complete");
  debug.line();
}

Debug.h

#ifndef DEBUG_H
#define DEBUG_H

class Debug {
  private:
    bool state;
  public:
    Debug();
    void init();
    void message(const char *str);
    void message(int);
    void line();
};

#endif

Debug.cpp

#include "Debug.h"
#include <Arduino.h>

Debug::Debug() : state(false) {}

void Debug::init() {
  if (state == false){
    Serial.begin(9600);
    state = true;
  }
}
void Debug::message(const char *messageChar) {
  if (state){
    const char *p;
    p = messageChar;
    while (*p) {
        Serial.print(*p);
        p++;
    }
  }
}
void Debug::message(int messageInt) {
  if (state){
    Serial.print(messageInt);
  }
}
void Debug::line() {
  if (state){
    Serial.println();
  }
}

Box.h

#ifndef BOX_H
#define BOX_H

#include "Debug.h"

class Box {  
  private:
    Debug debug;
  public:
    Box(Debug &debug);
    void init();
};

#endif

Box.cpp

#include "Box.h"
#include <Arduino.h>

Box::Box(Debug &debug):
  debug(debug)
{}

void Box::init(){
  // Switches
  pinMode(28, INPUT_PULLUP);

  debug.message("Box intialized");
  debug.line();
}

所以上面的代码输出到串口:

Setup Complete

如果我将Box::init()修改为

void Box::init(){
  // Switches
  pinMode(28, INPUT_PULLUP);

  debug.init();
  debug.message("Box intialized");
  debug.line();
}

我得到了我想要的:

Box initialized
Setup Complete

如果我摆脱 Box 构造函数 class 而改为

void Box::init(Debug &debug){
  this->debug = debug;
  
  // Switches
  pinMode(28, INPUT_PULLUP);

  debug.message("Box intialized");
  debug.line();
}

通过 Main.ino 调用

void setup(){
  debug.init();
  box.init(debug);
  debug.message("Setup Complete");
  debug.line();
}

我又得到了想要的回复。我不明白为什么我的第一次尝试不起作用,也不明白什么是最佳实践。我将不胜感激任何指导。

您的代码中有两个 Debug 值。一个全球,一个成员 Box class.

这是两个不同的值,因为 Box 创建或复制一个值来创建它自己的值,还有一个全局值。

解决方案是包含引用或指针。

这是带有参考的示例:

class Box {  
  private:
    Debug& debug;
    //   ^---- there
  public:
    Box(Debug &debug);
    void init();
};

如果你想让Box仍然可以赋值,那么使用一个指针:

class Box {  
  private:
    Debug* debug;
    //   ^---- now it's a star
  public:
    Box(Debug &debug);
    void init();
};

Box::Box(Debug &debug):
  debug(&debug)
{} //   ^----- here, we take the address of the debug variable.

由于引用是不可变的,因此您失去了语言的一些重要特性:赋值。

struct thing {
    int& ref;
};

int main () {
    int a, b;
    thing t1{a}, t2{b};

    t1 = t2; // ERROR!
}

赋值后 t1.ref 指向 b

指针的语法更难,语义更难猜测。然而,它们在赋值方面做得很好,因为它们给了你更多的自由:

struct thing {
    int* ptr;
};

int main () {
    int a, b;
    thing t1{&a}, t2{&b};

    t1 = t2; // Works, t1.ptr points to b
}