У меня есть ситуация, когда у меня есть класс на микроконтроллере, который имеет дело с широтно-импульсной модуляцией. Чрезвычайно упрощенный пример:Как избежать виртуальных функций в этом случае?
class MotorDriver
{
int pin_;
public:
MotorDriver(int pin);
void init();
void start();
void stop();
void changeDutyCycle(int dc);
};
У него есть функции для инициализации, запуска, остановки и изменения pwm. Если подключить 4 двигателей с микроконтроллером, я буду создавать 4 экземпляры этого класса и поместить их в массив, а затем вызывать функции, как возникает
motors[0].changeDutyCycle(50);
motors[1].changeDutyCycle(40);
....
Проблема, потому что не существует универсального способа, чтобы настроить таймер на указанный микроконтроллер. Например, одному мотору придется использовать Timer3, в то время как другому мотору придется использовать Timer4. Различные таймеры имеют разные размеры битов, регистры, каналы, контакты ... Я хочу иметь возможность писать пользовательские функции для каждого таймера, но все же могу поместить все объекты в один и тот же массив и функции вызова на них, то есть
class MotorDriver
{
void changeDutyCycle(int dc) = 0;
};
class MotorDriver1 : public MotorDriver
{
void changeDutyCycle(int dc)
{
TIM3->CCR2 = dc;
}
};
class MotorDriver2 : public MotorDriver
{
void changeDutyCycle(int dc)
{
TIM4->CCR1 = dc;
}
};
MotorDriver1 md1();
MotorDriver2 md2();
MotorDriver* mds[] = { &md1, &md2 };
int main()
{
mds[0]->changeDutyCycle(10);
mds[1]->changeDutyCycle(20);
}
Я знаю, что могу достичь того, чего хочу с помощью виртуальных функций. Эта функция короткая и будет вызываться часто, поэтому цена виртуальных функций высока. Есть ли способ избежать их в этом случае или другой шаблон дизайна? Цель состояла в том, чтобы иметь многоразовый код, который легко использовать снаружи. Наличие всего, что мне нужно в массиве, намного облегчает многое.
Edit: Я знаю об этом сообщении Avoiding virtual functions но ответ, который относится к тому, что мне нужно состояние:
Если вы находитесь в ситуации, когда каждый цикл за подсчеты вызовов, то есть вы делаете очень небольшая работа в вызове функции, и вы вызываете из своего внутреннего цикла в критическом для производительности приложении, вам, возможно, нужен совсем другой подход.
Я предлагаю использовать идентификатор MotorDriver при создании нового двигателя. ID является частной переменной, мы используем ID для доступа к массиву таймера. Это означает, что каждый таймер отображает 1 идентификатор. –
Наверное, таймеры совсем не такие, и вы преувеличиваете необходимость относиться к ним по-другому? Альтернативный способ записи драйверов, когда у вас есть x аппаратных периферийных устройств с точно таким же макетом регистра, - это что-то вроде [this] (http://stackoverflow.com/questions/29034417/c-preprocessor-generate-macros-by- concatenation-and-stringification/29035658 # 29035658), где вы просто передаете указатель на смещение базы регистров. Тогда код драйвера для разных таймеров будет на 100% идентичным. – Lundin