Правильное использование * и & при передаче объектов в методах.

В C# указатели несколько незнакомы, хотя я понимаю эту концепцию. Правильно ли создавать методы следующим образом и передавать объект (в качестве параметра), созданный по ссылке? Если нет, то ответьте, пожалуйста, как это сделать правильно.

Инициализировать объект

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

Метод: (используйте * для указателя?)

boolean initializeMusicPlayer(Adafruit_VS1053_FilePlayer *mp, uint16_t baudRate) {

    musicPlayerSerialPort.begin(baudRate);
    // инициализируем музыкальный проигрыватель
    if (!mp->begin()) { // инициализируем музыкальный проигрыватель
        Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
        return false;
        //пока (1);
    }
    Serial.println(F("VS1053 found"));

    mp->sineTest(0x44, 500);    // Издаем звуковой сигнал, указывающий, что VS1053 работает

    if (!SD.begin(CARDCS)) {
        Serial.println(F("SD failed, or not present"));
        return false;
        //пока (1); // больше ничего не делаем
    }
    Serial.println("SD OK!");
    // Установка громкости для левого и правого каналов. меньшие цифры == громче!
    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;
}

Вызвать метод (использовать амперсанд для передачи текущего созданного метода по ссылке?)

if(initializeMusicPlayer(&musicPlayer, 9600) == true) {
    tempString = tempString + "MusicPlayer initialized!";
    Serial.println(tempString);
    //при добавлении ЖК-дисплея распечатываем приведенное выше на ЖК-дисплее и удаляем последовательную печать
}   

, 👍3


1 ответ


Лучший ответ:

7

Реализованный вами метод передача по указателю является одним из двух обычных методов, да. Второй — передача по ссылке и предназначен для C++, а не C.

По сути, конечный результат обоих методов один и тот же, благодаря синтаксическому слову «сахар»; сильно отличается, и последний может быть предпочтительнее только по этой причине.

Ваш метод:

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

function(&myObject);

Метод передачи по ссылке:

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

function(myObject);

Как видите, необходимость конвертировать объект в указатель с помощью & теперь отпала. Это значительно упрощает его использование людьми, не имеющими навыков программирования, поскольку он скрывает от них весь механизм указателей.

Кроме того, внутри ваша функция теперь рассматривает ob как просто еще один объект, использующий ., а не указатель на объект и необходимость использования ->. Обратите внимание, что вы можете использовать оператор ссылки только в прототипе функции, а не в переменной или чем-то подобном — он предназначен исключительно для передачи объектов и переменных в функции. Если вы хотите затем сохранить указатель в переменной, вам все равно придется получить адрес:

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

Как видите, два разных использования & сбивают с толку. Однако по сути: если он находится в прототипе функции, то это оператор передача по ссылке. Если это где-то еще, это оператор получить адрес (или, конечно, логическое И).

Сохранение указателя может быть полезно, если вы хотите впоследствии выполнить другие действия с тем же объектом, особенно если вы сами работаете с классом. Например, я часто пишу код, подобный следующему:

class foo {
    private:
        bar *ob; // Указатель на другой объект типа "bar"
    public:
        foo(bar *inob) : ob(inob) {}
        foo(bar &inob) : ob(&inob) {}

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

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

Тогда у вас есть выбор конструкторов:

bar myBar;
foo myFoo(myBar);

// ... позже ...
myFoo.something();

или

bar myBar;
foo myFoo(&myBar);

// ... позже ...
myFoo.something();

и пользователю не нужно запоминать, что ему нужно использовать — подойдет то, что он попробует.

,

Итак, то, что я сделал, правильно, хотя и не обязательно лучший метод. Моя мысль об указателе заключалась в том, что, поскольку этого игрока можно вызывать десятки раз, я хочу, чтобы он каждый раз вызывал один и тот же объект. Правильно ли написан мой код для этой цели?, @dinotom

Мне кажется, все в порядке. Хотя я обычно передаю объект конструктору и сохраняю его как указатель в создаваемом классе, а затем получаю доступ к объекту через этот указатель - это означает, что вам не нужно затем передавать один и тот же объект снова и снова., @Majenko

@Маженко... Спасибо, еще один пункт. Поместить класс в заголовочный файл проекта?, @dinotom

Это зависит от того, как вы собираетесь использовать класс. Если вы хотите использовать его в других местах, возможно, стоит превратить его в библиотеку — создайте файл .h с объявлением класса и файл .cpp с фактическими методами класса. Если вы не хотите разбивать его на отдельные объявление и определение, вам следует оставить его в своем эскизе. Даже в этом случае может быть полезно разделить его, если в вашем эскизе есть несколько исходных файлов, и все они хотят его использовать., @Majenko

Я думаю, стоит упомянуть важное различие между указателем и ссылкой: указатель может быть NULL (т.е. 0 означает, что он ни на что не указывает), тогда как ссылка всегда должна ссылаться на реальную переменную (хотя технически это можно обмануть). компилятор, но никто этого не сделает). Лично я всегда предпочитаю использовать ссылки, если не хочу разрешать NULL., @jfpoilpret