crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в данную темуНачать новую тему
> Статический полиморфизм
Litkevich Yuriy
  опции профиля:
сообщение 30.12.2020, 7:53
Сообщение #1


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9666
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Пытаюсь понять, как можно в С++ реализовать полиморфизм времени компиляции для следующей задачи.

Имеется шина 1-Wire (из названия понятно, что она однопроводная, несчитая общего проводника).
Имеется N устройств на этой шине.
Шина должна знать какие устройства на ней есть.
Устройства должны знать на какой шине сидят.
Устройства пользуются функциями-членами шины для выполнения своих задач.


class OneWireDevice;

class OneWire
{
    bool addDevice(OneWireDevice *device);
    bool removeDevice(OneWireDevice *device);
    
    List<OneWireDevice *> deviceList(); // List - предполагаемый шаблонный контейнерный класс
    
    void foo();
}

class OneWireDevice
{
    OneWireDevice(OneWire *awire = 0);
    
    OneWire* wire();
    
    void bar()
    {
        wire()->foo();
    }
}



Особенность 1-Wire:
1) может быть реализована програмным дрыганьем ножки микроконтроллера;
2) может быть реализована через аппаратный UART, т.е. передавая определённый байт
огибающая сигнала будет повторять необходимую форму ипульсов 1-Wire.
3) сам UART можно реализовать программно дрыгая ножку микроконтроллера.

Т.о. возможны следующие схемы реализации 1-Wire:
OneWire(Pin);
OneWire(UART);
OneWire(SoftUART(Pin));

Сейчас у меня сделан абстрактный класс 1-Wire и наследники, реализующие один из 3-х способов.

class OneWire {...};

// -1-
class OneWirePin: public OneWire
{
    OneWirePin(Pin *pin);
};

//...
Pin *pin = new Pin();
OneWirePin *wire(pin);    


// -2-
class OneWireUart: public OneWire
{
    OneWireUart(Uart *uart);
};

//...
Uart *uart = new Uart();
OneWirePin *wire(uart);

// -3-
class OneWireUartPin: public OneWire
{
    OneWireUartPin(SoftUart *uart)
};

//...
Pin *pin = new Pin();
SoftUart *uart = new SoftUart(pin);
OneWirePin *wire(uart);



// ======================================

Всё бы хорошо, но наличие виртуальных функций для микроконтроллерного применения - плохо.
это замедляет код и раздувает его из-за vtable. Сначала хотел реализовать OneWire на шаблонах.

Однако споткнулся на том, что класс OneWireDevice должен пользоваться OneWire и, в частности, возвращать OneWire.
т.е. сделать сам OneWire шаблонным не получится, т.к. для метода OneWireDevice::wire() надо будет аргумент шаблона указывать.

Может кому-то подобную иерархию со статическим полиморфизмом доводилось реализовывать?


В идеале хотелось бы получить такой код применения:
// -1-
Pin *pin = new Pin();
OneWire *wire = new OneWire<Pin *>(pin);

// или

Pin pin;
OneWire *wire = new OneWire<Pin>(pin);


// -2-
UART *uart = new Uart();
OneWire *wire = new OneWire<UART *>(uart);

// или

UART uart;
OneWire *wire = new OneWire<UART >(uart );


// -3-
SoftUART *uart = new SoftUART();
OneWire *wire = new OneWire<SoftUART *>(uart);

// или

SoftUART uart;
OneWire *wire = new OneWire<SoftUART>(uart );


Сообщение отредактировал Litkevich Yuriy - 30.12.2020, 12:12
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 30.12.2020, 8:34
Сообщение #2


фрилансер
******

Группа: Участник
Сообщений: 2913
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


Цитата
но наличие виртуальных функций для микроконтроллерного применения - плохо.
это замедляет код и раздувает его из-за vtable.


немного замедлит (вряд ли заметно), но не раздует. А вот шаблоны раздуют программный код сильно. И отлаживать их будет сложнее. Компилить дольше тоже.

А стандарт C++ какой?

Если 17, то std::variant подойдёт


если что, реализацию std::variant можно найти, если компилятор его ещё не умеет )

Сообщение отредактировал Алексей1153 - 30.12.2020, 9:23
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 30.12.2020, 9:18
Сообщение #3


фрилансер
******

Группа: Участник
Сообщений: 2913
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


https://onlinegdb.com/r1J-2ctTv

#include <iostream>
#include <variant>
#include <algorithm>
#include <vector>

class EmptyDevice
{
public:
    void print_me()const
    {
        std::cout<<"EmptyDevice"<<'\n';
    }
};

class Pin
{
public:
    void print_me()const
    {
        std::cout<<"Pin"<<'\n';
    }
};

class UART
{
public:
    void print_me()const
    {
        std::cout<<"UART"<<'\n';
    }
};

class SoftUART
{
public:
    void print_me()const
    {
        std::cout<<"SoftUART"<<'\n';
    }
};


using ControlWay=std::variant<EmptyDevice,Pin,UART,SoftUART>;


class DeviceList
{
    std::vector<ControlWay*> m_list;
public:
    bool addDevice(ControlWay* device)
    {
        m_list.push_back(device);
        return true;
    }
    
    bool removeDevice(ControlWay* device)
    {
        m_list.erase(std::remove(m_list.begin(),m_list.end(),device),m_list.end());
        return true;
    }
    
    void print_me()const
    {
        for(auto* d:m_list)
        {
            std::visit([](auto& device)
            {
                device.print_me();
            },*d);
        }
    }
};

int main()
{
    DeviceList m_DeviceList;
    
    m_DeviceList.addDevice(new ControlWay{Pin{}});
    m_DeviceList.addDevice(new ControlWay{UART{}});
    m_DeviceList.addDevice(new ControlWay{SoftUART{}});

    m_DeviceList.print_me();
    
    //m_DeviceList.removeDevice(d1);
    //m_DeviceList.removeDevice(d2);
    //m_DeviceList.removeDevice(d3);
    
    //не забыть сделать освобождение памяти либо заюзать std::unique_ptr

    return 0;
}


Цитата
Pin
UART
SoftUART


Сообщение отредактировал Алексей1153 - 30.12.2020, 9:19
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 30.12.2020, 12:10
Сообщение #4


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9666
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(Алексей1153 @ 30.12.2020, 11:18) *
using ControlWay=std::variant<EmptyDevice,Pin,UART,SoftUART>;
что значит using в этом месте?

Цитата(Алексей1153 @ 30.12.2020, 11:18) *
m_DeviceList.addDevice(new ControlWay{Pin{}});
почему здесь Pin с фигурными скобками?
Если я правильно понял, то ControlWay с фигурными потому что он union или нет?

Сообщение отредактировал Litkevich Yuriy - 30.12.2020, 12:11
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 31.12.2020, 12:03
Сообщение #5


фрилансер
******

Группа: Участник
Сообщений: 2913
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


Цитата(Litkevich Yuriy @ 30.12.2020, 14:10) *
что значит using в этом месте

объявление алиаса (более удобная замена typedef)

Цитата(Litkevich Yuriy @ 30.12.2020, 14:10) *
почему здесь Pin с фигурными скобками


{} - пустой список инициализации

Pin{} - создание экземпляра класса Pin с конструктором по умолчанию

ControlWay{Pin{}} - создание экземпляра класса ControlWay, конструктор принимает ссылку на объект класса Pin

union тут не используется
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 2.1.2021, 1:22
Сообщение #6


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9666
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(Алексей1153 @ 31.12.2020, 14:03) *
Pin{} - создание экземпляра класса Pin с конструктором по умолчанию
чем отличается от традиционного Pin() ?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 2.1.2021, 13:12
Сообщение #7


фрилансер
******

Группа: Участник
Сообщений: 2913
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


Litkevich Yuriy, можно сказать, что ничем, но в редких случаях компилятор может перепутать с синтаксисом вызова или объявления функции. Со списком инициализации всё всегда однозначно
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 25.2.2021, 8:40