Как перебрать объекты или передать объект функции?

Я не уверен, что это больше вопрос C++, но я просмотрел оба и до сих пор не знаю.

У меня есть скетч, который управляет 6 шаговыми двигателями с помощью библиотеки AccelStepper, и, чтобы сократить код, я хотел бы просто перебрать их или передать их функции по отдельности. Все они инициализируются с разными параметрами, а затем помещаются в массив.

Однако я получаю сообщение об ошибке "запрошено преобразование из SomeClass() в нескалярный тип SomeClass" или "запрошено преобразование из SomeClass (*)()" в нескалярный тип SomeClass" в зависимости от что я пытаюсь.

У меня есть опыт работы с C и Java, немного с C++, и я думал, что это будет простой массив указателей, но я не могу найти правильную комбинацию.

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

SomeClass classA();
SomeClass classB();

// ошибка: запрошено преобразование из 'SomeClass()' в нескалярный тип 'SomeClass'
SomeClass things[2] = {classA, classB};

int init(class SomeClass thing) {
    std::cout << "Setting up thing ";
    thing.setFoo(100);
}

int main() {

    for (int i=0; i < 2; i++) {
        things[i].setFoo(100);
    }

    // не удалось преобразовать 'classA' из 'SomeClass (*)()' в 'SomeClass'
    init(classA);

    return 0;
}

И просто для полноты мои файлы классов, которые являются упрощенными версиями класса AccelStepper:

SomeClass.h:

#include <stdlib.h>

class SomeClass
{
public:
    SomeClass();

    void    setFoo(float foo);
};

SomeClass.cpp:

#include <stdlib.h>
#include <string>
#include <iostream>
#include "SomeClass.h"

SomeClass::SomeClass()
{
}

void SomeClass::setFoo(float foo)
{
    std::cout << "foo ";
}

Надеюсь, кто-то не против объяснить то, что, наверное, действительно просто и очевидно! :)

, 👍0


1 ответ


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

1

В вашем наброске есть пара фундаментальных ошибок. В основном ваша конструкция экземпляров вашего класса:

SomeClass classA();
SomeClass classB();

Они рассматриваются как функции, возвращающие объект SomeClass, а не конструкторы SomeClass. Вместо этого они должны просто читать:

SomeClass classA;
SomeClass classB;

Что касается остального, вам гораздо лучше использовать указатели на классы — это значительно упрощает их передачу. Например, ваш массив будет выглядеть так:

SomeClass *things[2] = {&classA, &classB};

Это массив указателей на объекты. Он просто сохраняет адреса, по которым они находятся, а не дублирует объекты в новые объекты в массиве.

Тогда ваш цикл будет работать следующим образом:

for (int i=0; i < 2; i++) {
    things[i]->setFoo(100);
}

Обратите внимание на использование -> вместо ., поскольку вы используете указатель на объект.

Аналогично ваша функция init() будет выглядеть так:

int init(SomeClass *thing) {
    Serial.println("Setting up thing");
    thing->setFoo(100);
}

init(&classA);

Однако, если вы никогда не собираетесь использовать с ним содержимое своего массива, вы можете использовать ссылку вместо указателя:

int init(SomeClass &thing) {
    Serial.println("Setting up thing");
    thing.setFoo(100);
}

init(classA);

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

,

Спасибо за Ваш ответ! Я должен был включить более сложный конструктор, фактические объекты создаются, например: AccelStepper stepperA(AccelStepper::HALF4WIRE, MotorPinA1, MotorPinA3, MotorPinA2, MotorPinA4); Это все еще держится с вышеизложенным?, @jbyrnes

Из моего опыта работы с C это выглядит как указатель на массив указателей: SomeClass *things[2] = {&classA, &classB}; Отличается ли он в C++?, @jbyrnes

Нет, это просто массив [] указателей *. Если бы это был указатель на массив указателей, то это был бы SomeClass **things[2] — точно такой же, как в C., @Majenko

Если ваш конструктор принимает параметры, вы добавляете параметры. Если нет, то нет. Это немного сбивает с толку, и я понятия не имею, почему они так поступили., @Majenko

@Majenko спасибо за ваш ответ. Это очень помогло. Однако мне было интересно, вместо массива указателей со ссылками на объекты класса, не могли бы мы просто иметь массив этих объектов и ссылаться на них как myObj &obj = arr[idx];?, @Phil