2015-02-10 2 views
0

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

//My Arduino based device has a real time clock for which I use a library 
#include <RTClib.h> 
RTC_DS3234 RTClock(PIN_CLOCK_CS); // uses SPI 
DateTime dt = RTClock.now(); 
// I also have written a logging class which is a singleton 
#include <Logger_SD.h> 
Logger_SD::Instance()->initializeSD(PIN_SD_CS,PIN_CLOCK_CS,&dt); 

Таким образом, мой класс журнала теперь использует указатель на dt для его даты при генерации сообщений журнала. К сожалению, каждый раз, когда я вызываю регистратор, я должен обновить dt, чтобы он имел правильную дату и время.

dt = RTClock.now(); 
Logger_SD::Instance()->msgL(INFO,F("Setting Up MPU6050 Gyro.")); 

Я хотел бы передать метод RTClock.now(), которая всегда возвращает DateTime в Logger_SD так что он может получить его собственное проклятое время. К сожалению, существует много видов RTC. Я мог бы сделать:

RTC_DS1307 RTClock(0x68); // Uses i2c 
// or 
RTC_DS3231 RTClock(0x68); // Also I2c, but does more. 
// Lots more. 
// then again... 
DateTime dt; 
dt = RTClock.now(); 
// I'd like to do something like: 
DateTime myNow() return RTClock.now(); 
Logger_SD::Instance()->initializeSD(PIN_SD_CS,PIN_CLOCK_CS,&myNow); 

Все это есть метод сейчас(), который возвращает DateTime, но как я прохожу метод сейчас(), чтобы Logger_SD без необходимости иметь специальный случай для каждого класса объектов RTC ?

Мой Logger_SD.h выглядит немного как это, если это помогает:

class Logger_SD { 
    public: // I don't quite understand the mechanics here, but it works great. 
     static Logger_SD* Instance(); 
     bool initializeSD(const uint8_t, const uint8_t disable_chip_select,DateTime* dt); 
     void msgL(LOG_LEVEL logLevel,const __FlashStringHelper *format, ...); 
     // ... 
    private: 
     Logger_SD(){}; 
     Logger_SD(Logger_SD const&){}; 
     Logger_SD& operator=(Logger_SD const&){}; 
     static Logger_SD* m_pInstance; 
     DateTime *_dt; 
     // ... 
}; 

Я надеюсь, что это было ясно.

Вот простой пример:

class RTC1 { 
    public: 
    char now() { return 'A';} 
}; 
class RTC2 { 
    public: 
    char now() { return 'B';} 
}; 
class Logger { 
    public: 
    void ini(char f()) { logTime = &f ;} // this doesn't work 
    char (*logTime)(); 
}; 
void setup(){ 
    Serial.begin(57600); 
    RTC1 myRTC1; 
    Logger myLogger; 
    myLogger.ini(&myRTC1.now); 
    Serial.println(MyLogger.logTime()); // Should print 'A' 
    // now on a diffent kind of RTC for the same Logger 
    RTC2 myRTC2; 
    myLogger.ini(&myRTC2.now); 
    Serial.println(MyLogger.logTime()); // Should print 'B' 
} 

ответ

1

myRTC1.now не может быть преобразован в указатель на функцию - это метод класса. Для вызова now вам понадобится экземпляр myRTC1. То, что вы пытаетесь сделать как есть, невозможно.

Что вы можете вместо этого сделать, это взять std::function:

class Logger { 
public: 
    using LogFunc = std::function<char()>; // any function that takes no 
              // args and returns a char 

    template <typename F> 
    void ini(F&& f) { logTime = std::forward<F>(f); } 
    LogFunc logTime; 
}; 

Что вы можете назначить таким образом:

Logger myLogger; 
myLogger.ini(std::bind(&RTC1::now, myRTC1)); 
myLogger.ini([&]{ return myRTC2.now(); });