Как унаследовать класс, требующий &foo() в своем конструкторе?
Общее
У меня есть библиотека с конструктором класса class Math(&foo1,&foo2);
, которую я хотел бы поместить в библиотеку для class Algebra()
, где foo1
и foo2
определены в Algebra.cpp
Мой текущий конструктор Algebra::Algebra():Math(&Algebra::foo1,&Algebra::foo2)
возвращает ошибку в Arduino IDE в результате:
ошибка: нет соответствующей функции для вызова 'Math::Math(void (Algebra::*)(long unsigned int, byte), byte (Algebra::*)(long unsigned int))':Math(&Algebra::foo1, &Algebra::foo2)
Мета-заметка: Я считаю, что это по теме, потому что я имею дело конкретно с разработкой кода для Arduino Mega с использованием библиотек и аппаратных компонентов, разработанных для Arduino. Если я ошибаюсь, и есть лучший обмен для этого вопроса, пожалуйста, дайте мне знать
В частности,
Я пишу библиотеку для объединения I2C FRAM от Adafruit с Расширенной библиотекой базы данных (я проверил, что библиотеки работают при независимом вызове в скетче, но я хотел бы объединить их, чтобы их было легче наследовать в [Big_Machine_api.h], который я сделаю позже) Я тестирую свою библиотеку с помощью этого скетча:
/*
EDB_AT24C1024.pde
Расширенная библиотека базы данных + тестовый эскиз Adafruit_FRAM_I2C EEPROM
Страница проекта библиотеки расширенной базы данных находится здесь:
http://www.arduino.cc/playground/Code/ExtendedDatabaseLibrary
Страница проекта библиотеки Adafruit_FRAM_I2C находится здесь:
https://github.com/adafruit/Adafruit_FRAM_I2C
*/
#include "Arduino.h"
#include <Wire.h>
#include <Adafruit_FRAM_I2C_EDB.h>
#define TABLE_SIZE 131072
// Произвольное определение записи для этой таблицы.
// Это следует изменить в соответствии с вашими потребностями в записи.
struct LogEvent {
int id;
unsigned long Rotations;
}
logEvent;
// Создать объект EDB с соответствующими обработчиками записи и чтения
Adafruit_FRAM_I2C_EDB db;
// Запустить демо
void setup() {
Serial.begin(115200);
Serial.println("DONE");
}
void loop() {
}
Мой файл ADAFRUIT_FRAM_I2C_EDB.h:
#ifndef ADAFRUIT_FRAM_I2C_EDB_h
#define ADAFRUIT_FRAM_I2C_EDB_h
#include <Arduino.h>
#include <Adafruit_FRAM_I2C.h>
#include <EDB.h>
#define MB85RC_DEFAULT_ADDRESS (0x50) /* 1010 + A2 + A1 + A0 = 0x50 default */
class Adafruit_FRAM_I2C_EDB : public EDB {
public:
Adafruit_FRAM_I2C_EDB(uint8_t addr = MB85RC_DEFAULT_ADDRESS);
void getDeviceID(uint16_t *manufacturerID, uint16_t *productID);
private:
Adafruit_FRAM_I2C _fram;
uint8_t _FRAMaddr;
void writer(unsigned long address, byte data);
byte reader(unsigned long address);
};
#endif
Мой файл ADAFRUIT_FRAM_I2C_EDB.cpp:
#include "Arduino.h"
#include "Adafruit_FRAM_I2C.h"
#include "EDB.h"
#include "Adafruit_FRAM_I2C_EDB.h"
Adafruit_FRAM_I2C_EDB::Adafruit_FRAM_I2C_EDB(uint8_t addr)
:_FRAMaddr(addr),EDB(&Adafruit_FRAM_I2C_EDB::writer, &Adafruit_FRAM_I2C_EDB::reader) {
_fram = Adafruit_FRAM_I2C();
_fram.begin(_FRAMaddr);
}
void Adafruit_FRAM_I2C_EDB::getDeviceID(uint16_t *manufacturerID, uint16_t *productID) {
_fram.getDeviceID(manufacturerID, productID);
}
void Adafruit_FRAM_I2C_EDB::writer(unsigned long address, byte data) {
_fram.write8(address, data);
}
byte Adafruit_FRAM_I2C_EDB::reader(unsigned long address) {
return _fram.read8(address);
}
Полный список ошибок:
C:[...]\Arduino\libraries\Adafruit_FRAM_I2C_EDB\Adafruit_FRAM_I2C_EDB.cpp:16:84: note: candidates are:
In file included from C:[...]\Arduino\libraries\Adafruit_FRAM_I2C_EDB\Adafruit_FRAM_I2C_EDB.cpp:3:0:
C:[...]\Arduino\libraries\EDB-master/EDB.h:54:5: note: EDB::EDB(void (*)(long unsigned int, uint8_t), uint8_t (*)(long unsigned int))
EDB(EDB_Write_Handler *, EDB_Read_Handler *);
^
C:[...]\Arduino\libraries\EDB-master/EDB.h:54:5: note: no known conversion for argument 1 from 'void (Adafruit_FRAM_I2C_EDB::*)(long unsigned int, byte) {aka void (Adafruit_FRAM_I2C_EDB::*)(long unsigned int, unsigned char)}' to 'void (*)(long unsigned int, uint8_t) {aka void (*)(long unsigned int, unsigned char)}'
C:[...]\Arduino\libraries\EDB-master/EDB.h:50:7: note: constexpr EDB::EDB(const EDB&)
class EDB {
^
C:[...]Arduino\libraries\EDB-master/EDB.h:50:7: note: candidate expects 1 argument, 2 provided
C:[...]Arduino\libraries\EDB-master/EDB.h:50:7: note: constexpr EDB::EDB(EDB&&)
C:[...]\Arduino\libraries\EDB-master/EDB.h:50:7: note: candidate expects 1 argument, 2 provided
exit status 1
Error compiling for board Arduino/Genuino Mega or Mega 2560.
@ATE-ENGE, 👍0
1 ответ
Вы просто передаете переменные родительскому конструктору в списке инициализации дочернего элемента. Не нужно никаких квалификаций или чего-то подобного.
Вот пример, который компилируется:
class Math {
private:
int _foo1;
int _foo2;
public:
Math(int &foo1, int &foo2) : _foo1(foo1), _foo2(foo2) {}
};
class Algebra : public Math {
private:
int myFoo1 = 12;
int myFoo2 = 34;
public:
Algebra() : Math(myFoo1, myFoo2) {}
};
Конструктор Math принимает два целых числа, переданных по ссылке. Список инициализации конструктора Algebra вызывает родительский конструктор Math с двумя собственными целыми числами-членами, которые затем автоматически передаются по ссылке, поскольку именно это вызывает конструктор.
Однако ваша проблема заключается не в этом. Вы спрашиваете об одном, а затем показываете ошибку, которая относится к совершенно другой проблеме.
У вас есть конструктор (на самом деле любая функция будет делать то же самое), который ожидает пару указателей на две функции:
void (*)(длинное беззнаковое целое, uint8_t)
uint8_t (*)(длинное беззнаковое целое)
То есть вам нужны две функции, такие как:
void reader(unsigned long a, uint8_t b) {
}
и
uint8_t writer(unsigned long a) {
return 3;
}
Но вместо этого вы пытаетесь передать функции-члены класса. Проблема здесь в том, что хотя они выглядят одинаково, поскольку они являются членами класса, они не одинаковы.
Любая функция-член класса имеет дополнительный подразумеваемый параметр, который является указателем на содержащий экземпляр класса и называется this
. Так что ваши функции на самом деле выглядят примерно так:
void reader(Adafruit_FRAM_I2C_EDB *this, unsigned long a, uint8_t b) {
}
и
uint8_t writer(Adafruit_FRAM_I2C_EDB*this, unsigned long a) {
return 3;
}
(Примечание: это всего лишь приближение — на самом деле все гораздо сложнее, но это служит иллюстрацией проблемы). Как видите, это не соответствует ожидаемому результату, и поэтому вы не можете передать эти функции родительскому конструктору — они просто неверны.
Это часто встречающаяся проблема — часто наблюдается при попытке использовать функцию-член класса с attachInterrupt()
. Вы просто не можете этого сделать. Или не так, во всяком случае.
Единственный способ передать функцию-член напрямую — сделать ее статической
. Тогда она будет действовать как обычная функция, и параметра this
не будет. Однако она может действовать только на другие статические
переменные и функции. Поэтому ее использование требует немного большей осторожности — плюс, конечно, статические
функции и переменные являются общими для всех экземпляров класса.
- Является ли использование malloc() и free() действительно плохой идеей для Arduino?
- Как читать и записывать EEPROM в ESP8266
- Какой реальный срок службы EEPROM?
- Как запомнить значения переменных после перезагрузки платы Arduino Uno R3
- Получить доступ к EEPROM ATtiny с помощью кода Arduino?
- Очистка EEPROM
- Как сохранить переменную с плавающей запятой в EEPROM
- Spiffs против Eeprom на esp8266