Russian Qt Forum
Ноябрь 22, 2024, 12:31 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: Нетипичное наследование  (Прочитано 16120 раз)
ecspertiza
Супер
******
Offline Offline

Сообщений: 1053


С уважением, мастер конфетного цеха!


Просмотр профиля
« : Октябрь 10, 2017, 18:52 »

Реализую у себя в коде возможность выполнения неких команд. Команда перед запуском должна быть проверена, может ли она быть запущена.

Есть вот такой пример
Код:
#include <iostream>
#include <vector>

class BaseCommand {

    public:
        enum CommandType {
            TypeA,
            TypeB
        };

        BaseCommand() = default;

        virtual void execute() = 0;
        virtual bool dublicated() = 0;
        virtual BaseCommand::CommandType commandType() = 0;
};

class CommandA : public BaseCommand {

    public:
        CommandA() = default;

        void execute() override {
            std::cout << "execure CommandA" << std::endl;
        }

        bool dublicated() override {
            return true;
        }

        BaseCommand::CommandType commandType()
        {
            return TypeA;
        }
};

class CommandB : public BaseCommand {

    public:
        CommandB() = default;

        void execute() override {
            std::cout << "execure CommandB" << std::endl;
        }

        bool dublicated() override {
            return false;
        }

        BaseCommand::CommandType commandType()
        {
            return TypeB;
        }
};

std::vector<BaseCommand *> m_arr;

bool checkCommand(BaseCommand *command)
{
    if (!command)
        return false;

    if (!command->dublicated()) {
        for (std::vector<BaseCommand *>::iterator it = m_arr.begin() ; it != m_arr.end(); ++it)
            if ((*it)->commandType() ==  command->commandType()) {
                return false;
            }
    }

    m_arr.push_back(command);

    return true;
}

int main(int argc, char *argv[])
{

    CommandA *ca = new CommandA;
    if (checkCommand(ca)) {
        ca->execute();
    }else {
        delete ca;
    }

    CommandB *cb = new CommandB;
    if (checkCommand(cb)) {
        cb->execute();
    }else {
        delete cb;
    }

    return 0;
}

Функция checkCommand просто для примера, она будет сильно расширена, и хочется что бы она работала с базовым классом. В текущем коде не нравится то, что команды создаются до того как произошла проверка на запуск. Вопрос как в данном случае можно выполнить эту проверку до того как создан экземпляр команды?
Думал сделать dublicated статичной, но статичные виртуальные функции не поддерживаются. 
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #1 : Октябрь 11, 2017, 07:59 »

Можно не создавать команду, можно проверить по типу сначала

Код:
bool checkCommand(BaseCommand::CommandType type)
{
        for (std::vector<BaseCommand *>::iterator it = m_arr.begin() ; it != m_arr.end(); ++it)
            if ((*it)->commandType() ==  type) {
                return false;
            }
    }
    return true;
}
« Последнее редактирование: Октябрь 11, 2017, 10:22 от ssoft » Записан
ecspertiza
Супер
******
Offline Offline

Сообщений: 1053


С уважением, мастер конфетного цеха!


Просмотр профиля
« Ответ #2 : Октябрь 11, 2017, 09:56 »

Необходимо проверить флаг dublicated, если он false то запретить создавать дубликат команды. В примере выше не понятно откуда берется переменная command.
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #3 : Октябрь 11, 2017, 10:27 »

Наверное так  Непонимающий

Код:
int main(int argc, char *argv[])
{
    if ( checkCommand( BaseCommand::TypeA ) )
         m_arr.push_back( new CommandA );
...
}
Записан
ecspertiza
Супер
******
Offline Offline

Сообщений: 1053


С уважением, мастер конфетного цеха!


Просмотр профиля
« Ответ #4 : Октябрь 11, 2017, 10:29 »

Теперь нет возможности получить из потомка флаг dublicable ;-) То есть он по дефолту проверяется. А проверка должна происходить в зависимости от флага deblicable потомка.
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #5 : Октябрь 11, 2017, 10:38 »

Если dublicable является неизменяемым свойством для каждого типа команд, то можно метод оформить, как статический.

Код:
class BaseCommand
{
...
    static bool dublicated ( Type type )
    {
        switch ( type )
        {
    ...
        }
    }
};

Если же это свойство конкретного экземпляра команды (экземпляры одного класса могут быть как dublicated, так и нет), тогда уже придется создавать экземпляр.
Записан
ecspertiza
Супер
******
Offline Offline

Сообщений: 1053


С уважением, мастер конфетного цеха!


Просмотр профиля
« Ответ #6 : Октябрь 11, 2017, 10:58 »

Изменяемо для каждого типа.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #7 : Октябрь 11, 2017, 13:47 »

Изменить архитектуру, заменив функцию checkCommand на
Код
C++ (Qt)
template <class Command>
std::shared_ptr<BaseCommand> createCommand()
{
   std::shared_ptr<BaseCommand> command = std::make_shared<Command>();
   if (!command->dublicated()) {
       for (std::vector<BaseCommand *>::iterator it = m_arr.begin() ; it != m_arr.end(); ++it)
           if ((*it)->commandType() ==  command->commandType()) {
               return null_ptr;
           }
   }
 
   m_arr.push_back(command);
 
   return command;
}
 
int main(int argc, char *argv[])
{
 
   auto ca = createCommand<CommandA>();
   if (ca)
       ca->execute();
 
   auto cb = createCommand<CommandB>();
   if (cb)
       cb->execute();
 
   return 0;
}
 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
ecspertiza
Супер
******
Offline Offline

Сообщений: 1053


С уважением, мастер конфетного цеха!


Просмотр профиля
« Ответ #8 : Октябрь 11, 2017, 13:53 »

m_ax, если не ошибаюсь тут тоже есть создание команды, потом проверка. И в случае если проверка не прошла, command будет автоматически удален. Буду мудрить с типами и switch.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #9 : Октябрь 11, 2017, 13:58 »

m_ax, если не ошибаюсь тут тоже есть создание команды, потом проверка. И в случае если проверка не прошла, command будет автоматически удален. Буду мудрить с типами и switch.
Конечно есть создание команды, ведь далее вызывается её метод (а как его вызвать без создания объекта?) Улыбающийся
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
ecspertiza
Супер
******
Offline Offline

Сообщений: 1053


С уважением, мастер конфетного цеха!


Просмотр профиля
« Ответ #10 : Октябрь 11, 2017, 14:03 »

Статик :-)

Вообще не хватает мета информации о типе, которую можно было бы проверять. Задал свойства команды в мета информацию. Проверил ее, она не изменяема и статична для каждого типа. При этом эту мета информацию можно было бы для потомков переопределять.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #11 : Октябрь 11, 2017, 15:56 »

Вообще не хватает мета информации о типе, которую можно было бы проверять. Задал свойства команды в мета информацию. Проверил ее, она не изменяема и статична для каждого типа. При этом эту мета информацию можно было бы для потомков переопределять.
Ну это типичный паттерн type_traits и плюс немного меташаблонной магии от boost::variant и boost::static_visitor

Код
C++ (Qt)
#include <iostream>
#include <string>
#include <boost/variant.hpp>
#include <memory>
#include <vector>
 
struct typeA_teg{};
struct typeB_teg{};
 
 
class BaseCommand
{
public:
   typedef boost::variant<typeA_teg, typeB_teg> command_type;
 
   BaseCommand() = default;
   virtual void execute() = 0;
   virtual  command_type commandType() = 0;
};
 
class CommandA : public BaseCommand {
 
   public:
       CommandA() = default;
 
       void execute() override {
           std::cout << "execure CommandA" << std::endl;
       }
 
       BaseCommand::command_type commandType()
       {
           return typeA_teg();
       }
};
 
class CommandB : public BaseCommand {
 
   public:
       CommandB() = default;
 
       void execute() override {
           std::cout << "execure CommandB" << std::endl;
       }
 
       BaseCommand::command_type commandType()
       {
           return typeB_teg();
       }
};
 
 
template <class>
struct command_traits;
 
template <>
struct command_traits<CommandA>
{
   static constexpr bool is_dublicated = true;
   typedef typeA_teg command_type;
};
 
 
template <>
struct command_traits<CommandB>
{
   static constexpr bool is_dublicated = false;
   typedef typeB_teg command_type;
};
 
 
template <class Command>
struct is_same_command_type : public boost::static_visitor<bool>
{
   typedef typename command_traits<Command>::command_type command_type;
 
   bool operator()(command_type) const
   {
       return true;
   }
 
   template <class T>
   bool operator()(T) const
   {
       return false;
   }
};
 
std::vector<std::shared_ptr<BaseCommand>> m_arr;
 
template <class Command>
bool checkCommand()
{
 
   if (!command_traits<Command>::is_dublicated) {
       for (auto & c : m_arr)
       {
           if (boost::apply_visitor(is_same_command_type<Command>(), c->commandType())
               return false;
       }
   }
 
   m_arr.push_back(std::make_shared<Command>());
 
   return true;
}
 
Писалось на коленке, могут быть опечатки  Улыбающийся
« Последнее редактирование: Октябрь 11, 2017, 16:21 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
ecspertiza
Супер
******
Offline Offline

Сообщений: 1053


С уважением, мастер конфетного цеха!


Просмотр профиля
« Ответ #12 : Октябрь 11, 2017, 16:49 »

Спасибо, гляну этот паттерн.
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #13 : Октябрь 11, 2017, 17:07 »

Статик :-)

Вообще не хватает мета информации о типе, которую можно было бы проверять. Задал свойства команды в мета информацию. Проверил ее, она не изменяема и статична для каждого типа. При этом эту мета информацию можно было бы для потомков переопределять.

В класс добавьте статичных констант и переопределяйте их в потомках. Правда не очень понятно, как вы это всё использовать хотите.
Записан

Пока сам не сделаешь...
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #14 : Октябрь 11, 2017, 17:17 »

Код
C++ (Qt)
#include <iostream>
 
using namespace std;
 
template<bool isDup>
class Command
{
public:
static bool dublicated() { return isDup; }
};
 
class CommandA : public Command<true>
{
};
 
class CommandB : public Command<false>
{
};
 
int main()
{
cout << CommandA::dublicated() << endl;
cout << CommandB::dublicated() << endl;
 
return 0;
}
 
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.139 секунд. Запросов: 23.