Ответы пользователя по тегу C++
  • Почему нельзя передавать лямбду как аргумент шаблона?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    #include <iostream>
    
    template <class Body>
    void call(const Body& body) {
        body();
    };
    
    void test() {
      std::cout << "function" << std::endl;
    }
    
    int main() {
      call(test);
      call([]() {
        std::cout << "lambda" << std::endl;
      });
      return 0;
    }


    Дело в том, что лямбда — это объект неизвестного класса с операцией (). И только так её вызывают.
    Ответ написан
  • Правилен ли такой подход к разбиению C приложения на модули?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Смотря в чём задача.
    Возможно, нет никаких проблем.
    Возможно, удастся вытащить общую функциональность в defines.h.
    Возможно, удастся каким-то образом разорвать порочный круг. Например, в ООП это можно делать через интерфейс.
    Ответ написан
  • Как сделать так, чтобы CodeBlocks не ставил знаки?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Settings → Editor → General Settings (стоит по умолчанию) → Editor Settings (стоит по умолчанию) → Indent Options → Brace completion

    5cfa263e49d5b731760499.png
    Ответ написан
  • Исключение. Что это значит?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Это значит: вы «сломали» память. Как правило, разыменованием «висячего» указателя или вылетом за пределы массива.
    Ответ написан
  • Как вычислить интеграл с помощью формулы Симпсона?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Перед нами типичная студенческая работа.

    Первое, что нужно сделать,— вынести расчёт интеграла в отдельную функцию. Помимо прочего, она должна принимать параметром n — количество точек разбиения. И проверьте, разумеется, работоспособность.

    Затем поднимаемся на более высокий уровень — налаживаем алгоритм выдерживания точности. Я бы написал так.
    n := 10
    yНовое := расчёт(n)
    повтор
      n := n·2
      yСтарое := yНовое
      yНовое := расчёт(n)
    пока |yСтарое - yНовое| > эпсилон
    вывести/вернуть yНовое

    Сможешь перевести на Си?
    Ответ написан
  • Почему Segmentation fault?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Переменная run ничему не присвоена.
    Ответ написан
  • Как к четырем элементам массива добавить ещё два?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Нужен или массив с запасом (например, на 6 мест), или динамический (например, std::vector).
    Си++ — язык достаточно низкого уровня, и сам программист видит, где там память динамически выделяется, а где выделена заранее.
    Ответ написан
  • Объясните разбор файла mainwindow.h в QT по шагам?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    // Защита от повторного включения
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    // Пара include’ов
    #include <QWidget>
    #include <QMainWindow>
    
    // Определение UI-класса наперёд, чтобы визуальное редактирование не приводило
    // к крупным перекомпиляциям
    namespace Ui {
    class MainWindow;
    }
    
    // Собственно класс формы
    class MainWindow : public QMainWindow
    {
        // Макрос, который добавляет файл в компиляцию MOC’ом,
        // а также реализует пару функций
        Q_OBJECT
    
    public:
        // Конструктор-деструктор.
        // Форма семантически не эквивалентна parent’у,
        // потому конструктор explicit
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    // Слоты — фишка Qt, которая обрабатывается MOC’ом
    private slots:
    
    
    private:
        // Указатель на UI (для него в Qt есть ещё одна программа, UIC)
        Ui::MainWindow *ui;
    };
    
    // Защита от повторного включения
    #endif // MAINWINDOW_H


    Что ещё написать?

    Определение класса наперёд не мешает писать указатели и ссылки.

    Конструктор explicit запрещает неявное преобразование. Explicit имеет смысл, если возможен вызов конструктора с одним параметром. Правило таково: ставь explicit, если твой объект по смыслу не эквивалентен единственному параметру конструктора. Например, Ratio(int x);, но explicit Array(int x);: при построении рационального числа из целого будет полный эквивалент, но при построении массива — нет.
    Ответ написан
  • Почему пробел заменяется на W?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Пробел не isupper.

    Расчёт тут идёт в знаковом типе, потому *i + key - 97 < 0

    Существует два метода деления с остатком, в x86 встроен тот, где знак остатка равняется знаку делимого (а неполное частное — результат округления к нулю). Именно его впоследствии кодифицировали в Си99. Значит, (*i + key - 97) % 26 < 0

    Это значит, что результат преобразования будет меньше 97 = 'a'. Например, 'W'.

    Ах да. В Си можно написать (*i + key - 'a') % 26 + 'a'.
    Ответ написан
  • Как быстро выбирать подстроку у строки?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Использовать кольцевой буфер. Придётся пописать немного, но на что это нужно и какова будет сложность остальных работ?
    Ответ написан
  • Как грамотно осуществить декомпозицию?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    typedef struct ttime {
    Си, на ++ не нужен typedef.
    И используй наконец тэги для кода.

    int hours; int minute; int sec;
    Странное именование, обычно пишут hour.

    struct date {
    ttime time;

    которая в свою очередь входит в состав структуры Date.
    Странно, ведь это не дата, а скорее Clock — часы.

    Методы позволяют изменять текущее время

    Ну и где тут измерение?

    Моя архитектура.
    1. Время. Получение времени из системы, сравнение, вывод в консоль.
    2. Часы. Хранят последнее время. Команда «tick» — получить время, сравнить с последним, при неравенстве — сохранить новое и вывести его в консоль.
    3. Внешний цикл (может быть как в часах, так и снаружи). Часы тикают, делают небольшую задержку и проверяют на нажатие клавиши.
    Пять объектов никак не будет, да и Date нужно только в том случае, если вы реально работаете с датой. Я бы, чтобы докинуть количество объектов до нужного, сделал бы дату (date), время (time) и дату-время (stamp).

    Для турнира единоборств (для простоты — без весовых категорий).
    • Fighter: имя, всякая информация про него вроде города, клуба и титулов.
    • Stub: указатель на Fight + enum (Winner/Loser) — откуда берётся участник. Указателя на Fight нет — тогда TBD (то есть не определился).
    • Participant: указатель на Fighter + структура stub.
    • Fight: номер, два Participant, дата/время, кто победил (0/1), причина победы (ещё не проводился, KO, TKO, по очкам, неявка…)
    • Tournament: содержит список боёв и таблицу результатов.

    Можно также разорвать кольцо зависимостей, наладив интерфейс FightInfo, сделав в Stub FightInfo*, а не Fight*, и чтобы Fight реализовывал FightInfo.
    Ответ написан
  • Как разобраться, что происходит в этом заголовочном файле?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Учи понятие «единица компиляции». Тут, к сожалению, есть и вещи, которые должны быть в CPP-файле, и вещи, которые должны быть в H-файле.

    #pragma pack(1)
    Структуры данных нам нужны «один в один», без байтов заполнения.

    struct FileHeader 
    struct MAPINFO

    Формат BMP. Не забывай, что формат BMP записывается с нижней строки!

    Функция Open читает картинку «один в один», Save пишет «один в один», GetMapInfo и GetFH выдают какие-то заголовки нашего BMP.

    Остаётся GetMap(), который, по идее, должен выдавать матрицу цветов, но реально действует только для 32-битного BMP и никак не инкапсулирует ни ширину-высоту матрицы, ни тот факт, что формат BMP пишется с нижней строки.

    За этот код — тройка с минусом.

    А теперь чего ваш код НЕ поддерживает, но, по идее, должен, чтобы выполнить вашу задачу.
    1. Создание BMP нужного размера с нуля, а не загрузка из файла.
    2. Инкапсулировать матрицу пикселей. Желательно так, чтобы был быстрый доступ к строкам как к буферам в памяти, для простоты переноса информации из старого BMP в новый, на 30×30 пикселей больший.
    3. Если вы ограниченно поддерживаете формат BMP — вылетать с ошибкой, если версия неподдерживаемая (например, не то количество цветов).

    Задача именно своими силами наладить поддержку BMP? А то в Builder’е есть TBitmap.
    Ответ написан
  • Как организовать указатели в си?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Дело тут в очерёдности операций.
    Сначала вычисляются правые одноместные, потом левые.

    Надо (**h)[1] = 0;.
    Ответ написан
  • Qt checkbox this combobox?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Через сигналы-слоты способа не вижу.
    Унаследоваться от QStandardItemModel, присосаться на setModelData.
    А ещё лучше унаследоваться от QAbstractTableModel и переопределить все эти data(), flags()…
    Ответ написан
  • Передача ссылки на экземпляр объекта из конструктора?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Дело у вас вот в чём. Файл Part_Of_Word.h напоминает единицу компиляции (*.cpp), но имеет расширение заголовочного файла (*.h). После того, как вы удалили все его include’ы, эти функции просто перестали компилироваться.

    А до этого, вангую, у вас было два include’а — а значит, две копии одной функции из разных единиц компиляции. Тоже ошибка линкера.

    Решение: переименовать этот файл в cpp.
    Ответ написан
  • Как понять: массив указателей на объекты классов?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Вы тут просто не знаете, что такое указатель. А это, грубо говоря, адрес другого объекта в памяти.
    Операция new заводит объект в «куче», вызывает конструктор (если таковой есть) и возвращает указатель на него.
    И мы можем разыменовать указатель: пройти на тот объект, куда он указывает, и сделать с ним что-то. В Си разыменование — операция ->.

    Указатели не на абстрактный класс, а на вполне конкретный, a.

    a(int) — не конструктор копирования, а просто конструктор, делающий объект из int’а. Конструктор копирования всегда a(const a&). Отличается от других конструкторов тем, что автоматика его по возможности строит, но не всегда верно. В вашем объекте с одним полем int вполне себе построит без всяких проблем.

    Обычный указатель Си никоим образом не знает, есть объект или нет, и кто этот объект уничтожает. У вас это приводит к ошибке «утечка памяти»: теряется указатель на объект, и уже никак его не освободишь. Из-за небольшого размера и линейного характера программы неопасно, но всё-таки.
    Ответ написан
  • Почему 150/1000 == 0?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Потому что деление происходит int/int, то есть целочисленное.
    Надо 150.0/1000.

    Это известный глюк Си-подобных языков — a/b в зависимости от типа или деление, или неполное частное. В Паскале, например, неполное частное — a div b. В Си-подобных языках с динамической типизацией (JS) отказались от неполного частного, ибо мы тип плохо контролируем.
    Ответ написан
  • Как правильно передавать функцию как параметр C++?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Не забывайте, что у startManufacturing есть скрытый параметр this.

    Четыре варианта.

    1. Использовать указатель на метод App:
    Rest::function(char * function_name, int (App::* f)(String), App& object)
          // вместо App можно какой-то интерфейс, который App реализует
    …
    object.*f("string");
    ...
    bt_rest.function("", &App::startManufacturing, *this);


    2. Сделать startManufacturing static:
    class App {
      static int startManufacturing(String command)
    };


    3. Сделать обёртку с замыканием:
    Rest::function(char * function_name, int (*f)(String, void*), void*);
    
    void doStartManufacturing(String command, void* closure) {
      reinterpret_cast<App*>(closure)->startManufacturing(command);
    }
    ...
    bt_rest.function("startManufacturing", doStartManufacturing, this);


    4. «Избегай незнакомых женщин и глобальных переменных». Костыль, в общем.
    App app;
    int doStartManufacturing(String command) { return app.startManufacturing(command); }
    ...
    bt_rest.function("startManufacturing", doStartManufacturing);


    Ах да. Вы передаёте String’и по значению. Приспособлены они к такой передаче или всё же лучше по ссылке?
    Ответ написан
  • Как нарисовать линию с помощью алгоритма Брезенхема и гамма-коррекции в текстовом файле?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    Я бы работал по такой формуле:

    result = ((original / max)1 / gamma) · 255

    Original — это полученное алгоритмом Ву значение (float или хотя бы short!)
    max — максимально возможное значение original. Для short, например, это 65535.
    gamma — традиционно 2,2.
    Ответ написан
  • Как работает scanf в плюсах?

    @Mercury13 Куратор тега C++
    Программист на «си с крестами» и не только
    1. Для ввода строки использовать std::getline.
    2. Ну, в Си++ есть хорошо инкапсулированные строки, а в Си нет. Потому в Си очень сложно получить из потока строку неизвестной длины.
    Ответ написан