代码之家  ›  专栏  ›  技术社区  ›  Cammack

使用指针将变量用作类变量调用的*部分*

  •  -4
  • Cammack  · 技术社区  · 7 年前

    我试图在函数参数中使用指针从类中读取变量,如下所示:

    void Function(int (*Argument)) {
        Variable = Object*Argument.ClassVariable;
    }
    

    注意:我这样做的原因是,在允许用户更改该类变量值之前,我可以将旋转编码器位置的值设置为以前的类变量值。这样,当用户循环使用类变量进行设置时,每个变量的起始位置就是保存的值。

    类对象已命名 Object1 ,则, Object2 等 我要从每个对象读取的变量命名为 ClassVariable 。 调用函数时,我将使用 Function(ClassNumber);

    如果 ClassNumber 13 在调用函数时,我希望 Variable 使等于 Object13.ClassVariable

    这可能吗?

    其他信息:

    整个班级都是公共的。

    类对象的构造函数(注意,这是arduino, byte 是8位无符号):

      Modes(byte hue, byte sat, byte val, int del, bool hROal, bool hset, bool sset, bool vset, bool dset) {
        hueVal = hue;
        satVal = sat;
        valVal = val;
        delVal = del;
        hueROallow = hROal;
        hSet = hset;
        sSet = sset;
        vSet = vset;
        dSet = dset;
      }
    

    每个类对象都是一个单独的“模式”,用户可以选择。这个 Argument 我打算在函数中使用当前选择的“模式编号”。

    完整代码(很大程度上是一项正在进行的工作)

    #include <SPI.h>
    #include <Wire.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_SH1106.h>
    
    const byte Button2 = 8;
    
    const byte EncApin = 3;           // EncApin **MUST BE interrupt**
    const byte EncBpin = 4;           // These are the three pins the encoder A/B & button are connected to
    const byte EncButt = 2;           //
    
    static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};   // array to set encoder H/L sequence
    byte encVal;          // initialises reading from encoder
    
    Adafruit_SH1106 display(0);   // Initialise display? (On SPI OLED screens this sets the MOSI/CLK/DC/RST/CS pins)
    
    
    int displayVal; // to store the current output value for display
    String displayMode;
    byte mode = 1;              // set mode 0 at beginning
    byte qtyModes = 3;          // set number of modes that may be selected here
    
    byte setMode = 1;
    byte qtySetModes = 4;       // set number of sub-modes for setting values
    
    ///// FUNCTION PROTOTYPES ///////// must be declared here to allow the class to use them
    void EncReading(); 
    void EncReadingRO();
    
    ////////////////////////////////////////////////////////
    ////////////// ******** CLASSES ********* //////////////
    ////////////////////////////////////////////////////////
    class Modes {
    
      public:   // everything in the class below this will be available to the program outside of the class
    
      // Class Member Variables
      // These are initialized at startup
      byte hueVal;
      byte satVal;
      byte valVal;
      int delVal;
      bool hueROallow;
      bool hSet;
      bool sSet;
      bool vSet;
      bool dSet;
    
      byte CLdisplayVal;
      String displayDesc;
    
      // These maintain the current state
      unsigned long prevMillis;   // will store last time LED was updated
    
      // Constructor - creates a Mode & initializes the member variables and state
      // additional options for whether rollover of values allowed needed
      Modes(byte hue, byte sat, byte val, int del, bool hROal, bool hset, bool sset, bool vset, bool dset) {
        hueVal = hue;
        satVal = sat;
        valVal = val;
        delVal = del;
        hueROallow = hROal;
        hSet = hset;
        sSet = sset;
        vSet = vset;
        dSet = dset;
      }
    
      void Update() {
        switch (setMode) {
          case 1:           // case 1 for hue update
            if (hSet == 0) { 
              displayDesc = F(" HUE (FIXED)");
              CLdisplayVal = hueVal;
              break;
              }
            if (hueROallow == 1) EncReadingRO();
            else EncReading();
            hueVal = encVal;
            CLdisplayVal = encVal;
            displayDesc = F(" HUE");
            break;
    
          case 2:           // saturation update
            if (sSet == 0) { 
              displayDesc = F(" SATURATION (FIXED)");
              CLdisplayVal = satVal;
              break;
              }
            EncReading();
            satVal = encVal;
            CLdisplayVal = encVal;
            displayDesc = F(" SATURATION");
            break;
    
          case 3:           // value update
            if (vSet == 0) { 
              displayDesc = F(" BRIGHTNESS (FIXED)");
              CLdisplayVal = valVal;
              break;
              }
            EncReading();
            valVal = encVal;
            CLdisplayVal = encVal;
            displayDesc = F(" BRIGHTNESS");
            break;
    
          case 4:           // delay update
            if (dSet == 0) { 
              displayDesc = F(" TIMING (FIXED)");
              CLdisplayVal = delVal;
              break;
              }
            EncReading();
            delVal = encVal;
            CLdisplayVal = encVal;
            displayDesc = F(" TIMING");
            break;
          }
        displayReading();
      }
    
      void displayReading() {
        unsigned long currMillis = millis();        // These four lines are to
        static unsigned long prevMillis;                     // act as a delay, except
        if (currMillis - prevMillis >= 100) {   // without holding the execution          // note: encoder reading sensitive to delal changes, 100 not bad
          prevMillis = currMillis;                  // of other code
          display.fillRect(39, 30, 54, 24, BLACK);
          display.fillRect(0, 0, 128, 18, WHITE);
          display.setTextSize(1);
          display.setTextColor(BLACK);
          display.setCursor(1,1);
          display.println(displayMode);
          display.setCursor(1,10);
          display.println(displayDesc);
          display.setTextSize(3);
          display.setTextColor(WHITE);
          display.setCursor(39,30);
          display.println(CLdisplayVal);
          display.display();
        }
      }
    };
    
    
    ////////// Construct objects - this sets up the objects we want of the class 'Modes'
    // Modes modex(Hue0-255, Sat0-255, Val0-255, Del0-255, Hue rollover0/1, Hue settable0/1, Sset0/1, Vset0/1, Dse0/1
    Modes mode1(50, 100, 150, 100, 1, 1, 1, 1, 1);   // object 'mode1', initializing with H50, S100, V150, D100, hue rollover & settable options ON
    Modes mode2(55, 105, 155, 105, 0, 1, 1, 1, 1);
    Modes mode3(63, 73, 83, 93, 0, 1, 1, 1, 1);
    
    ////////////////////////////////////////////////////////
    ////////// ******** SETUP / LOOP ********* /////////////
    ////////////////////////////////////////////////////////
    
    void setup() {
      Serial.begin(115200);
      display.begin(SH1106_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)
      display.clearDisplay();
      display.display();
      pinMode(EncApin, INPUT_PULLUP);  // Turn on internal pullup resistors for encoder pins & buttons
      pinMode(EncBpin, INPUT_PULLUP);
      pinMode(Button2, INPUT_PULLUP);
      pinMode(EncButt, INPUT_PULLUP);
      attachInterrupt(digitalPinToInterrupt(EncApin), read_encoder, CHANGE);
      attachInterrupt(digitalPinToInterrupt(EncButt), encButtPress, FALLING);
      pciSetup(Button2);    // set up encApin for pin change interrupt
      encVal = mode1.hueVal;           // initialize the encoder to the mode1 setmode1 value
    }
    
    void loop() {
      switch(mode) {
        case 1:
          displayMode = F("MODE:Call it anything");
          mode1.Update();
          // add call to the mode 1 LED display function here, using mode1.xyz variables
          break;
    
        case 2:
          displayMode = F("MODE:Second");
          mode2.Update();
          // add call to the mode 2 LED display function here, using mode2.xyz variables
          break;
    
        case 3:
          displayMode = F("MODE:Third");
          mode3.Update();
          // add call to the mode 2 LED display function here, using mode2.xyz variables
          break;
    
      }
    
    Serial.print(F("Enc: "));
    Serial.print(encVal);
    Serial.print(F("    M1 H: "));
    Serial.print(mode1.hueVal);
    Serial.print(F("  S: "));
    Serial.print(mode1.satVal);
    Serial.print(F("  V: "));
    Serial.print(mode1.valVal);
    Serial.print(F("  D: "));
    Serial.print(mode1.delVal);
    Serial.print(F("    M2 H: "));
    Serial.print(mode2.hueVal);
    Serial.print(F("  S: "));
    Serial.print(mode2.satVal);
    Serial.print(F("  V: "));
    Serial.print(mode2.valVal);
    Serial.print(F("  D: "));
    Serial.println(mode2.delVal);
    
    //  Serial.print(F("freeMemory()="));
    //  Serial.println(freeMemory());
    
    }
    
    ////////////////////////////////////////////////////////
    //////////// ******** FUNCTIONS ********* //////////////
    ////////////////////////////////////////////////////////
    
    ///// Function to set encVal, 0-255, NO rollover
    void EncReading() {
      int8_t encoderdata;
      encoderdata = read_encoder();                           // returns the +- value from the read_encoder function
      if (encoderdata) {                                      // if not equal to zero
        if (encVal+encoderdata>255 || encVal+encoderdata<0);    // these if/else statements clamp encVal to prevent byte rollover
        else {
          encVal += encoderdata;
        } // end else
      }
    }
    ///// Function to set encVal, 0-255, WITH rollover
    void EncReadingRO() {
      int8_t encoderdata;
      encoderdata = read_encoder();                           // returns the +- value from the read_encoder function
      if (encoderdata) {                                      // if not equal to zero
        encVal += encoderdata;
      }
    }
    
    ////////////////////////////////////////////////////////
    //////////// ******** INTERRUPTS ********* /////////////
    ////////////////////////////////////////////////////////
    
    /////// Pin Change Interrupt Setup Function /////////// called in void setup to set the selected pin as a PCI
    void pciSetup(byte pin)
    {
        *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
        PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
        PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
    }
    
    //////////// PCI Interrupt Sub Routines////////
    // ISR (PCINT0_vect) is ISR for D8-13 // ISR (PCINT2_vect) is ISR for A0-5 // ISR (PCINT2_vect) is ISR for D0-7 //
    ISR (PCINT0_vect) // handle pin change interrupt for D8 to D13 here, depending on which are set in void setup
     {    
      if(digitalRead(Button2) == LOW)
         buttonPress();
     }
    
    
    //////// Func for ENCODER button press ISR ****** CHANGE 'setMode' ***** ///////////////
    void encButtPress() {
      static unsigned long prevInterrTime = 0;
      unsigned long interrTime = millis();
      if (interrTime - prevInterrTime > 200) {
        setMode++;
        // *** ADD HERE *** need to set encVal to whatever the existing value is in the setMode being switched to
        if (setMode > qtySetModes) setMode = 1;
        prevInterrTime = interrTime;
        setPrevEncVal(mode);
      }
    }
    
    void setPrevEncVal(byte (*modeNum)) {
      switch (setMode) {
        case 1: encVal = mode&modeNum.hueVal; break;
        case 2: encVal = mode1.satVal; break;
        case 3: encVal = mode1.valVal; break;
        case 4: encVal = mode1.delVal; break;
      }
    }
    
    //////// Func for button press ISR ****** CHANGE 'mode' ***** ///////////////
    void buttonPress() {
      static unsigned long prevInterrTime = 0;
      unsigned long interrTime = millis();
      if (interrTime - prevInterrTime > 200) {
        mode++;           // increment 'mode'
        setMode = 1;      // reset 'setMode'
      }
      if (mode > qtyModes) mode = 1;
      prevInterrTime = interrTime;
    }
    
    //////// Func for +1/-1 encoder reading ISR ///////
    /* returns change in encoder state (-1,0,1) */
    int8_t read_encoder() {
      static uint8_t old_AB = 0;
      old_AB <<= 2;
      old_AB |= ((digitalRead(EncBpin))?(1<<1):0) | ((digitalRead(EncApin))?(1<<0):0);
      return ( enc_states[( old_AB & 0x0f )]);
    }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   JACH    7 年前

    回答问题:

    你不能,因为C++是一种编译语言 ,因此,函数、对象和变量的名称变得毫无意义(相反,它们只是地址)

    例如,您可以在代码中看到

     int myVariable = 6;
    

    但编译器会看到:

     mov [6], [0x6874]
    

    阅读 Compiled vs. Interpreted Languages 以供更多参考。

    [针对您的具体情况]

    如果你使用接口和工厂,你会过得更好。

    class Mode {
        virtual int getAttribute() = 0;
    }
    
    class AMeaningfulName : public Mode {
        int getAttribute()  { return 1; }
    }
    
    class SelectAnotherMeaningfulNamePlease : public Mode {
        int getAttribute() { return 2; }
    }
    
    class ModeFactory {
        Mode getMode(int userSelectedMode) {
    
            if (userSelectedMode == MODE_1) {
                return new AMeaningfulMode();
            } else if (userSelectedMode == MODE_2) {
                return new SelectAnotherMeaningulNamePlease();
            } else {
                //send an exception so the user knows he selected something invalid
            }
        }
    }
    
    
    ///now, in your main or elsewhere
    ModeFactory factory = new ModeFactory();
    Mode mode = factory.getMode(userSelectedValue);
    int theAtttributeIWanted = mode.getAttribute();
    

    查看虚拟函数 https://en.wikipedia.org/wiki/Virtual_function

    还有工厂模式 https://www.tutorialspoint.com/design_pattern/factory_pattern.htm