• Как лучше реализовать цепочку вызовов действий одного класса?

    Daniro_San
    @Daniro_San
    Программист
    А ещё лучше, что бы методы возвращали не указатель, а ссылку.
    ClassA &method1(const ClassA &c) 
    {
        //.... 
        return *this; 
    }
    
    // Использование
    a.method1().method3().method2().methodN();
    Ответ написан
    1 комментарий
  • Как лучше реализовать цепочку вызовов действий одного класса?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Это называется "fluent interface" или "method chaining".

    Все зависит от того, что вам нужно:

    В jQuery/JS или LINQ/C# возвращаются именно новые объекты.

    Хотя в том же EntityFramework есть Fluent API, где методы вызываются на некотором объекте контекста, который настраивается такой цепочкой. В этом случае лучше возвращать ссылку, как это принято делать при перегрузке операторов.
    Ответ написан
    1 комментарий
  • Какая есть самая простая книга по алгоритмам и структурам данных?

    MrNexeon
    @MrNexeon
    Когда то я задавался таким же вопросом.

    Для меня же было достаточно посмотреть на структуры данных и алгоритмы сортировок в действии.

    Во-вторых, так как я программирую на C++, у меня есть стандартная библиотека std, которая предоставляет мне реализации (интерфейс) всех алгоритмов и структур данных. Мне же остается понять что и в каких случаях лучше использовать.

    Книг по алгоритмам и структурам данных множество, но почти все они (о ужас!) довольно сложные.

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

    Долой формальность!
    Ответ написан
    4 комментария
  • Как правильно выводить информацию из QVector?

    @Free_ze
    Пишу комментарии в комментарии, а не в ответы
    Откройте для себя Model/View в Qt. В частности, ваша задачка с каталогами описана здесь.

    Вкратце: у вас есть модель, в котором вы связываете ваш способ хранения (QVector в вашем случае) со стандарным интерфейсомQAbstractItemModel (или его потомки QAbstractListModel, QAbstractTableModel или QAbstractTreeModel), который можно передать в один из стандартных вью-виджетов (QListView, QTableView, QTreeView). Реализовав интерфейс (переопределив виртуальные методы data и setData для role==Qt::DisplayRole и Qt::EditRole), вы можете просто изменять состояние модели, а вью-виджеты подхватят изменения автоматически.

    Кроме того, есть еще такая штука - QDataWidgetMapper. Он умеет привязывать виджеты (даже обычные, не View) к определенным полям в модели.
    Пример

    Пример объемный, но минимально полный, содержащий всю необходимую инфраструктуру. Допустим, мы хотим создать редактор для некоторых статей (блога?). Нам нужен простой класс Article, чтобы собрать в кучу данные о каждой отдельной статье:

    class Article
    {
    public:
        Article(int id, const QString& title, const QString& content) 
            : _id(id), _title(title), _content(content) {}
    
        int id() const { return _id; } 
        void setId(int id) { _id = id; }
    
        QString title() const { return _title; } 
        void setTitle(const QString& title) { _title = title; }
    
        QString content() const { return _content; }
        void setContent(const QString& content) { _content = content; }
    
    private:
        int     _id;
        QString _title;
        QString _content;
    };

    Для него напишем модель хранения этих статей - ArticlesModel, содержащей массив статей и методы для их добавления/удаления. Кроме того, для нее мы реализуем стандартный интерфейс QAbstractTableModel (методы rowCount, columnCount, data и setData), чтобы виджеты знали, как оттуда брать и как обновлять данные.

    class ArticlesModel :
            public QAbstractTableModel
    {
    public:
        ArticlesModel(QObject *parent=nullptr);
    
        void addArticle(const Article& art);
        void removeArticle(int id);
    
        //QAbstractTableModel interface implamentation
        int rowCount(const QModelIndex &/*parent*/) const override;
        int columnCount(const QModelIndex &/*parent*/) const override;
    
        bool data(QModelIndex& index, const QVariant &value, int role) const override;
        QVariant setData(QModelIndex& index, int role) override;
        
    private:
        std::vector<Article> _articles;
    };
    
    // =================================================================
    
    ArticlesModel(QObject *parent/*=nullptr*/) 
        : QAbstractTableModel(parent)
    {
    }
    
    void ArticlesModel::addArticle(const Article& art) {
        _articles.push_back(art);
    }
    void ArticlesModel::removeArticle(int id) {
        auto found = std::find_if(begin(_articles), end(_articles), 
                                [id](const Article& art) {
                                    art.id() == id;
                                });
        if (found != std::end(_articles)) {
            _articles.erase(artIt);
        }
    }
    
    
    int ArticlesModel::rowCount(const QModelIndex &/*parent*/) const override {
        return _articles.size();
    }
    int ArticlesModel::columnCount(const QModelIndex &/*parent*/) const override {
        return 2;
    }
    
    bool ArticlesModel::data(QModelIndex& index, const QVariant &value, int role) const override {
        if (!index.isValid) return QVariant();
    
        if (role == Qt::EditRole) {
            switch (column) {
                case 0: 
                    QVariant(_articles[index.row()].setTitle(value.toString()));
                    return true; 
                case 1:
                    QVariant(_articles[index.row()].setContent(value.toString()));
                    return true; 
            }
        }
        return false;
    }
    
    QVariant ArticlesModel::setData(QModelIndex& index, int role) override {
        if (!index.isValid) return QVariant();
    
        if (role == Qt::DisplayRole || role == Qt::EditRole) {
            switch (column) {
                case 0: return QVariant(_articles[index.row()].title()); 
                case 1: return QVariant(_articles[index.row()].content());
            }
        }
        return QVariant();
    }


    Тогда можно сделать так:

    // this - это какой-то родительский виджет
    
    auto titleEditor = new QLineEdit(this);
    auto contentEditor = new QTextEdit(this);
    
    QAbstractTableModel *model = new ArticlesModel(this);
    model->addArticle(Article(1, "Hello title", "Hello content"));
    model->addArticle(Article(2, "Another title", "Another content"));
    
    auto mapper = new QDataWidgetMapper(this);
    mapper->setModel(model);
    mapper->addMapping(titleEditor, 0);
    mapper->addMapping(contentEditor, 1);
    mapper->toFirst(); // Переключаемся на первый элемент модели


    Теперь мы можем добавлять/удалять статьи в model->add/removeArticle(const Article&), переходить с заметки на заметку с помощью mapper->setCurrentIndex(int index), менять содержимое заметок в редакторе.

    Можно добавить QListView, так же передать туда модель через setModel() и связать сигнал изменения текущего элемента списка с тем же действием mapper, добавить пару кнопок для добавления/удаления заметок и мы получим полноценный редактор.
    Ответ написан
    Комментировать
  • Как заинтересовать человека(студента) в IT?

    edli007
    @edli007
    full stack, team lead
    Сам не захочет, не начнет. Программирование это ад для обычного человека.
    Ответ написан
    Комментировать
  • Как заинтересовать человека(студента) в IT?

    sim3x
    @sim3x
    Не надо нам тут лишних людей
    Ответ написан
    Комментировать
  • Как выбирать направление архитектуры ООП приложения?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    и как отдельный класс-синглтон


    Зачем? Зачем сингелтон? Ответте на вопрос когда это нужно?

    Есть ли практики, которым следует придерживаться, чтобы сделать правильную и простую архитектуру?


    - Разделение ответственности - важный принцип инженерного дела в принципе.
    - Принципы SOLID - хорошо дают понять как работать с зависимостями и делать декомпозицию системы. Сильно пересекается с инкапсуляцией, полиморфизмом и разделением ответственности.
    - Паттерны GRASP - эдакая смесь принципов и паттернов, описывают нюансы цикла жизни объектов и их взаимодействия друг с другом.
    - Закон Деметры - про инкапсуляцию.
    - CQRS - подход по разделению операций записи и операций чтения. Естественно подход такой не работает если вам надо реализовать атомарную запись и чтение, но это минимальный набор задач.
    - Рефакторинг. Он нужен всегда. Его нужно делать по чуть-чуть когда видно что "уже мешает" или "можно было сделать лучше". Ну то есть это не переписывание всего и вся большими кусками, а маленькие изменения которые с течением времени эволюционно меняют архитектуру проекта. Возможно только если код покрыт тестами, это отдельная жирная тема.

    Не нужно знать "архитектуры", они являются лишь результатом соблюдение принципов. И уж тем более "паттерны" это лишь элементы архитектуры. Не нужно на них зацикливаться, это лишь словарь.

    https://en.wikipedia.org/wiki/Category:Programming...
    Ответ написан
    2 комментария
  • Как выводить std::cout из нескольких приложений в одно окно (консоль)?

    Rou1997
    @Rou1997
    Запустить оба процесса из третьей программы и перехватить вывод обоих, ОС это поддерживает.
    Ответ написан
    Комментировать
  • Как избавиться от привычки усложнять задачу?

    saboteur_kiev
    @saboteur_kiev Куратор тега Программирование
    software engineer
    У вас слишком много свободного времени, вот и не знаете куда девать.
    Ответ написан
    Комментировать
  • Можно ли на с++ написать прошивку для микроконтроллера?

    gbg
    @gbg Куратор тега C++
    Любые ответы на любые вопросы
    Ардуинская библиотека - это C++
    Ответ написан
    Комментировать
  • Есть ли набор паттернов для проектирования собственных GUI контролов из приметивов?

    tzlom
    @tzlom
    Не совсем ответ - но выкиньте MFC туда где ему место ещё 8 лет назад и используйте Qt + QML.
    Ответ написан
    Комментировать
  • Можно ли преобразовать VGA в DVI-D/HDMI?

    15432
    @15432
    Системный программист ^_^
    Если нельзя DVI-VGA, то купите переходник HDMI-VGA, сам такой использую
    Вот за 5 баксов:
    https://www.fasttech.com/products/0/10015144/27654...
    У меня такой, с аудио выходом:
    https://www.fasttech.com/products/0/10006755/15340...
    Ответ написан
    Комментировать
  • Допустимо ли ardruino в коммерческом проекте?

    @else2
    А я не соглашусь с предыдущими ораторами. Вы разбирали 3d принтеры? Wanhao duplicator 4 или 5, например. Спокойно себе построены на ардуино. Пятый так вообще использует родную ардуиновскую плату без модификаций. А промышленные принтеры построены на базе mini-itx материнских плат. Тоже моветон? Уже промышленный стандарт. Плюсы - замечательная ремонтопригодность даже при кз на шлейфах. Вытащил и заменил. Не нравятся программы на си - прошивайте в ардуино ассемблерный код.
    Если делать устройства для химической, нефтегазовой промышленности, для военных реализаций - безусловно ардуино не подойдёт. Для бытовой и любительской техники - вполне. Никаких затрат на разработку - сразу в производство и сразу получаешь деньги.
    Ответ написан
    2 комментария
  • Как разобраться в печатных платах?

    "Мне всегда интересно, как устроены платы"
    Фольгированный текстолит же.

    "подключаемые к ним детали"
    А это уже совершенно другой вопрос

    "Как например, взять и собрать своё устройство (может быть примитивное)"
    Ну, платы здесь - примерно последняя (как минимум в простых случаях) проблема.

    Стоит, думаю - ознакомиться с основами электроники (ну, я, для начала - вот буквально так и гуглил бы). Начиная с "поведения" отдельных компонентов.

    И да, возможно стоит поискать более специализированные ресурсы, включая всяческих "радиокотов" и easyelectronics (первое, что пришло в голову). На одном из них вроде даже неплохо описывали эти самые "основы"
    Ответ написан
    Комментировать
  • Как вычисляется время в электронике?

    @nirvimel
    На физическом уровне кварцевый генератор выдает сигнал строго определенной частоты. Эта частота резонанса в кристалле кварца, которая определяется только его физическими габаритами и (почти) не зависит от температуры, полей и прочих факторов внешней среды. По точности этот механизм совсем немного уступает атомным часам.
    Далее этот сигнал поступает на вход счетчика, который отчитывает количество тактов в единицу времени и генерирует прерывание, сигнализирующее об истечении единицы времени или инкрементирует регистр, в котором хранится значение времени в заданных единицах.
    Ответ написан
    1 комментарий
  • Обязательно ли программист должен уметь разбирать и собирать компьютер?

    Jump
    @Jump
    Системный администратор со стажем.
    Все зависит от требований работодателя.
    И все должно быть прописано в должностной инструкции.

    Кому то это надо, кому то нет, некоторым желательно чтобы программист умел компьютеры чинить, и проводку в офисе, ну и подметал по утрам, ибо дворника нет.
    В принципе это нормально. Совместительство нормальная и обыденная вещь.
    А вот устраивает оно вас или нет - решайте сами.
    Ответ написан
    Комментировать
  • Как понять, какие uart`ы софтверные а какие хардверные на Raspberry PI 3?

    @iv_k
    "как понять?"
    посмотреть в схему и в даташит на процессор.
    Ответ написан
    Комментировать
  • Почему goto зло?

    @iv_k
    goto - тяжелое наследие ассемблерщиков, переходящих на си.
    можно обойтись и без него.
    хотя.. гляньте ядро линукс, там goto полно.
    например вот так
    foo()
    {
       if(..)
       {
            goto err;
       }
       if (...)
       {
          goto err;
       }
        on_success();
        return ok;
    err:
        on_error();
        return error;
    }


    вот тут достаточно просто для понимания
    Ответ написан
    Комментировать
  • Почему goto зло?

    0xcffaedfe
    @0xcffaedfe
    Developer & Reverser
    goto не зло, просто им нужно уметь пользоваться, anyway компиль все равно вставит jmp если нужно. Да и вообще компиляторы нынче шибко умные.
    Оригинал вида:
    #include <iostream>
    void dd();
    
    int main(int argc, const char * argv[]) {
        
    s:
        if(rand() % 100 == 99){
            goto e;
        }
        goto s;
    e:
        return 0;
    }


    Кошерно превращает в обычный цикл:
    int _main(int arg0, int arg1) {
        do {
                rax = rand();
                temp_3 = rax % 0x64;
                if (temp_3 == 0x63) {
                    break;
                }
        } while (true);
        return 0x0;
    }


    ну и на асме.

    _main:
                        push       rbp
                        mov        rbp, rsp
                        sub        rsp, 0x10
                        mov        dword [ss:rbp+var_4], 0x0
                        mov        dword [ss:rbp+var_8], edi
                        mov        qword [ss:rbp+var_10], rsi
    _100000f66:       call       imp___stubs__rand
                        mov        ecx, 0x64
                        cdq        
                        idiv       ecx
                        cmp        edx, 0x63
                        jne        _100000f81
                        jmp        _100000f86
    _100000f81:       jmp        _100000f66
    _100000f86:       xor        eax, eax
                        add        rsp, 0x10
                        pop        rbp
                        ret
    Ответ написан
    9 комментариев