3

Coming from C#, pointers are somewhat foreign although I am grasping the concept. Is it proper to construct methods in the following manner and passing the object (as a parameter) constructed by reference? If not, then please answer how to do this properly.

Initialize the object

Adafruit_VS1053_FilePlayer musicPlayer =
    Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

Method: (use the * for pointer?)

boolean initializeMusicPlayer(Adafruit_VS1053_FilePlayer *mp, uint16_t baudRate) {

    musicPlayerSerialPort.begin(baudRate);
    // initialise the music player
    if (!mp->begin()) { // initialise the music player
        Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
        return false;
        //while (1);
    }
    Serial.println(F("VS1053 found"));

    mp->sineTest(0x44, 500);    // Make a tone to indicate VS1053 is working

    if (!SD.begin(CARDCS)) {
        Serial.println(F("SD failed, or not present"));
        return false;
        //while (1);  // don't do anything more
    }
    Serial.println("SD OK!");
    // Set volume for left, right channels. lower numbers == louder volume!
    mp->setVolume(20, 20);

    if (!mp->useInterrupt(VS1053_FILEPLAYER_PIN_INT)) {
        Serial.println(F("DREQ pin is not an interrupt pin"));
        return false;
    }
    return true;
}

Call the method (Use the ampersand to pass the currently created one by reference?)

if(initializeMusicPlayer(&musicPlayer, 9600) == true) {
    tempString = tempString + "MusicPlayer initialized!";
    Serial.println(tempString);
    //when adding lcd, print the above to lcd and remove the serial print
}   
6

The method you have implemented, passing by pointer, is one of the two normal methods, yes. The other is passing by reference and is specific to C++, not C.

Under the hood the end result is the same between the two methods, by the syntactic "sugar" is very different and the latter can be preferable for that reason alone.

Your method:

void function(whatever *ob) {
    ob->method();
}

function(&myObject);

The pass by reference method:

void function(whatever &ob) {
    ob.method();
}

function(myObject);

As you can see the need to convert the object into a pointer with & is now gone. That makes it much easier for people lacking in programming skills to use it since it hides the whole pointer mechanism from them.

Also, internally your function now treats ob as just another object using ., rather than a pointer to an object and needing to use ->. Note that you can only use the reference operator in a function prototype, not a variable or anything like that - it's purely for passing objects and variables to functions. If you want to then go and store the pointer in a variable you still then have to get the address:

void function(whatever &ob) {
    myObjectPointer = &ob;
}

As you see it gets confusing with the two different uses of &. Basically though: if it's in a function prototype it's the pass by reference operator. If it's anywhere else it's the get the address of operator (or a logical AND of course).

Storing the pointer can be useful if you want to then do other things later on with the same object, especially if you are yourself working with a class. For instance, I often write code similar to the following:

class foo {
    private:
        bar *ob; // Pointer to other object of type "bar"
    public:
        foo(bar *inob) : ob(inob) {}
        foo(bar &inob) : ob(&inob) {}

        void something() {
            ob->doSomething();
        }

        void somethingElse() {
            ob->doSomethingElse();
            ob->evenMoreThings();
        }
};

You then have a choice of constructors:

bar myBar;
foo myFoo(myBar);

// ... later ...
foo.something();

or

bar myBar;
foo myFoo(&myBar);

// ... later ...
foo.something();

and the user doesn't have to remember which they need to use - whichever they try will work.

  • So what I have done is correct, although not necessarily the best method. My thought with the pointer, was since that player can be called dozens of times, I want it to call the same object every time. Is my code written properly for that intent? – dinotom May 9 '16 at 18:00
  • Looks fine to me. Although I tend to pass an object to the constructor and store it as a pointer in the class I am making, then access the object through that pointer - means you don't have to then keep passing the same object over and over again. – Majenko May 9 '16 at 18:05
  • @Majenko...Thank you, one other item. Put the class in the projects header file? – dinotom May 9 '16 at 18:32
  • 1
    It depends how you are going to use the class. If you want to use it in other places it can be worth turning it into a library - have a .h file with the class declaration in it, and a .cpp file with the actual class methods. If you don't want to split it into separate declaration and definition then you should keep it in your sketch. It can still be useful to split it even then though if you have multiple source files in your sketch that all want to use it. – Majenko May 9 '16 at 18:34
  • 1
    I think it would be worth mentioning the important difference between a pointer and a reference: a pointer can be NULL (i.e. 0 meaning that it points to nothing) whereas a reference shall always refer to a real variable (although technically it is possible to trick the compiler but nobody would do that). Personally I always prefer using references if I don't want to allow NULL. – jfpoilpret May 9 '16 at 19:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.