Задать вопрос
Ответы пользователя по тегу C++
  • Почему 150/1000 == 0?

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

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

    @Mercury13
    Программист на «си с крестами» и не только
    Не забывайте, что у 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’и по значению. Приспособлены они к такой передаче или всё же лучше по ссылке?
    Ответ написан
    6 комментариев
  • Как нарисовать линию с помощью алгоритма Брезенхема и гамма-коррекции в текстовом файле?

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

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

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

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

    @Mercury13
    Программист на «си с крестами» и не только
    Есть такое понятие, как «принцип подстановки Барбары Лисков». Если подставить на место User класс Comparator, должно сойтись по типам. Но нет: User умеет сравнивать только с самим собой, а Comparator — с любым Comparator.

    Теоретически должно было бы подойти такое (так называемая контравариантность). Но не работает ни в Си++, ни в Яве.
    class ComparatorBase
    {
    public:
        virtual ~ComparatorBase() = default;
    };
    
    class Comparator : public ComparatorBase {
        public:
            virtual int compare(Comparator  *t)=0;
    };
    
    class User : public Comparator{
    public:
        int compare(ComparatorBase *u) override {
            return 1;
        }
    };

    А по возвращаемому значению (если возвращается ссылка/указатель) может быть ковариантность, и она работает и в Си++, и в Яве.
    class Father
    {
    public:
        virtual Father& foo();
        virtual ~Father() = default;
    };
    
    class Son : public Father
    {
    public:
        Son& foo() override;
    };


    Как обойти. Есть два способа.
    Способ 1. Пусть старой Явы.
    int User::compare(Comparator *u)
    {
        auto* v = dynamic_cast<User*>(u);
        if (!v)
            return false;
        return v->name > this->name;
    }


    Способ 2. Так называемый «странно рекуррентный шаблон».
    template <class T>
    class Comparator {
    public:
        virtual int compare(T *t)=0;
        virtual ~Comparator() = default;
    };
    
    class User : public Comparator<User> {
    private:
        std::string name;
    public:
        User(std::string name){this->name=name;}
        int compare(User *u);
        void showName(){std::cout<<"Name "<<this->name<<std::endl;}
    
    };
    
    int User::compare(User *u)
    {
        return u->name > this->name;
    }
    Ответ написан
    Комментировать
  • Какие есть способы перевода с одного типа данных в другой?

    @Mercury13
    Программист на «си с крестами» и не только
    1. С использованием функций преобразования типа, встроенных в Си++ или написанных пользователем. Это может делаться неявно, через C-style cast, через вызов конструктора, через операцию static_cast.
    2. С преобразованием указателя вниз по иерархии наследования, и особым поведением, если это не получилось, через операцию dynamic_cast и функцию dynamic_pointer_cast.
    3. С рассмотрением участка памяти как переменной несовместимого типа. Через union, const_cast, reinterpret_cast, C-style cast указателей.
    Ответ написан
    Комментировать
  • Как задать свойство класса экземпляром другого класса, если его значения не известны при инициализации?

    @Mercury13
    Программист на «си с крестами» и не только
    center_pt = *new Point(x/size, y/size);
    Утечка памяти. Никто в «си с крестами» за вас не будет подчищать все эти new.
    Правильно:
    center_pt = Point(x/size, y/size);
    (Ну и, разумеется, я не понимаю, что значат эти x/size и y/size, но шут с ним.)

    Примерно таким образом и происходит переприсваивание объектов, если им оставили таки операцию =. То есть…
    class Geolocator {
    public:
      Point coords;
      bool isReliable;
    
      Geolocator() : coords(0,0), isReliable(false) {}
    
      void getFromSensor() {
        coords = Point(100, 100);
        isReliable = true;
      }
    };


    Вариант 2. Через указатель, создание и уничтожение. Для простоты не буду это делать «руками», а воспользуюсь указателем единоличного владения unique_ptr.
    class Geolocator {
    public:
      std::unique_ptr<Point> coords;
    
      void getFromSensor() {
        Point pt(100, 100);
        if (coords) {
          *coords = pt;
        } else {
          coords.reset(new Point(pt));
        }
        // а если и операции = у Point нет, то можно
        // coords.reset(new Point(100, 100));
      }
    
      void declareUnreliable() {
        coords.reset();
      }
    };
    Ответ написан
    6 комментариев
  • Не заканчивается программа?

    @Mercury13
    Программист на «си с крестами» и не только
    Потому что конец консоли с клавиатуры зависит от ОС, и для Windows это Ctrl+Z.
    Нажатие ввода не передаёт в поток EOF.
    Ответ написан
    6 комментариев
  • Ввывод сообщения об успешном завершении программы в с++?

    @Mercury13
    Программист на «си с крестами» и не только
    Вопрос в буферизации потоков ввода-вывода. Разумеется, на Windows и OSX эти подробности устроены по-разному. Два модификатора, std::endl и std::flush, сбрасывают буфера.
    cout << "Кол-ва нат чис: " << std::flush;
        cin >> n;
        
        cout << sum(n) << std::endl;
    Ответ написан
    Комментировать
  • Можно ли число представить в виде float?

    @Mercury13
    Программист на «си с крестами» и не только
    Float содержит 23 бита мантиссы и неявную единицу. Порядок float запредельный и даже qword не упрётся в него.
    Это значит: всё, что дальше 23 бит от верхней единицы, должно быть нулём.

    bool isPreciseFloat(unsigned long long n)
    {
      // Простейшая проверка: стираем нижние 24 бита
      // Если в них вписываемся — ДА.
      unsigned long long n1 = n & ~((1ULL << 24) - 1);
      if (n1 == 0)
        return true;
    
      // Получаем верхнюю единицу
      // (можно также двоичным поиском, но я этого с листа не напишу)
      while (true) {
        unsigned long long n2 = n1 & (n1 - 1);
        if (n2 == 0)
          break;
        n1 = n2;
      }
    
      // Получаем маску всего, что ниже 23 бит от верхнего бита.
      n1 >>= 23;
      --n1;
    
      // Проверяем по маске
      return (n & n1) == 0;
    }


    Писал «с листа», могут быть ошибки.
    Ответ написан
  • Иероглифы вместо кириллицы в с++?

    @Mercury13
    Программист на «си с крестами» и не только
    Перед нами UTF-8. Перекодируйте исходник в рабочую кодировку (обычно DOS-866 или Windows-1251).

    Или работайте в широких строках. У меня на MinGW 5.3 получился вот такой исходник.
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        setlocale(LC_ALL, "rus");
        wcout << L"Превед!" << endl;
        return 0;
    }
    Ответ написан
  • Почему неправильный вывод значений в printf?

    @Mercury13
    Программист на «си с крестами» и не только
    У меня вышло: 0 1074266112 0 1074266112
    Или, в 16-й системе, 0 40080000 0 40080000

    Связано это с такими вещами.
    1. Аргументы типа float записываются в стеке как double.
    2. На x86 порядок байтов Intel (обратный).
    3. Дробные числа хранятся без ведущего разряда (который всегда 1), в формате мантисса-порядок-знак (на порядке байтов Intel).
    4. Для единицы (xxx·20) порядок будет 011…11.

    3 = 1,10…02·2¹, и с учётом отброшенного ведущего разряда мантисса будет 10…0.
    Порядок 011…11 + 1 = 10…0.

    С учётом обратного порядка байтов double 3,0 будет выглядеть так
    • 6 нулевых байтов — мантисса
    • 0000.1000: нижние полбайта — это мантисса, верхние — уже порядок
    • 0100.0000: бит знака и ещё семь битов порядка

    Получается 00.00.00.00.00.00.08.40.
    Разбиваем на два куска памяти по 4 байта.
    [00.00.00.00] [00.00.08.40]
    Опять-таки не забудем, что у целых тоже обратный порядок байтов — и получается 0 и 40080000.
    Ответ написан
    Комментировать
  • Почему не переполняется float?

    @Mercury13
    Программист на «си с крестами» и не только
    Представьте, у нас десятичная арифметика с тремя значащими цифрами. Соответственно, сложение работает не более чем с пятью цифрами: три собственно значащих, слева на перенос и справа на округление. То, что получилось, в любом случае будет округлено до трёх.
     99900000000000
    +             1,00
     -----------------
     9990   →   9,99e13

    Если сделать второе слагаемое покрупнее, то будет
     99900000000000
    +   50000000000
     -----------------
     9995   →   1,00e14 → переполнение


    То есть вот что надо добавить, чтобы случилось переполнение: в зависимости от настроек сопроцессора или ulp(FLT_MAX) (ULP = Unit of Last Place — цена младшего разряда на данном порядке), или ulp(FLT_MAX)/2.
    Ответ написан
    Комментировать
  • Зачем std::forward иметь две сигнатуры и явно указывать тип?

    @Mercury13
    Программист на «си с крестами» и не только
    std::forward предназначен для использования в шаблонах; без шаблона можно использовать старый добрый std::move.
    Кроме того, std::forward налажен таким образом, что шаблонный параметр надо указывать явно.

    Задача std::forward — передать далее простую или временную ссылку в зависимости от того, какую ссылку передаёт пользователь.
    Ответ написан
    6 комментариев
  • Написать программу, сильно тормозящую Windows?

    @Mercury13
    Программист на «си с крестами» и не только
    Много дёргать ввод-вывод. Например, помногу, в несколько потоков, читать диск.
    Если винт механический, Windows становится абсолютно неюзабельной.
    Ответ написан
    Комментировать
  • Как установить OpenCV для C++ в QT Creator?

    @Mercury13
    Программист на «си с крестами» и не только
    LIBS += -LC:/opencv/pro/lib -lxxx

    xxx — это имя файла с расширением a, без расширения и префикса lib.
    Если он libopencv_core.a, то надо -lopencv_core
    Ответ написан
    Комментировать
  • Почему запускается первым конструктор mainwindow.cpp?

    @Mercury13
    Программист на «си с крестами» и не только
    Я бы переписал архитектуру программы.
    1. Перед вами модальное окошко. Вот его и вызывайте, как модальное — au.exec().
    2. Чтобы проверить, что авторизация верна, надо соединиться. Так что сделайте невизуальный объект «соединение» и протащите в exec. Ну или создайте в exec.
    3. А уж там собирайте основную программу.
    QApplication a(argc, argv);
    FmAutoriz au;
    std::unique_ptr<SomeConnection> connection = au.exec();   // SomeConnection и exec придётся написать
    if (connection) {
      FmMain m(connection);
      m.show();
      return a.exec();
    } else {
      return 0;
    }
    
    std::unique_ptr<SomeConnection>FmAutoriz::exec()
    {
      bool b = QDialog::exec();
      if (b) {
        return std::move(this->connection);
          // connection — поле FmAutoriz.
          // Такой же unique_ptr, в обработчиках кнопок пытаемся создать соединение.
      } else {
         return nullptr;
      }
    }
    
    void FmAutorize_on_btOk_click()
    {
       connection = new SomeConnection();
       if (connection.connect(someLogin, somePassword)) {
          accept();
       } else {
          // сообщи об ошибке
       }
    }

    Вижу побочку этого (но, может, и не надо избавляться) — на панели задач анимацией сменяется кнопка с диалогом авторизации на кнопку с главным окном.
    Ответ написан
  • Как получить кол-во записей, которые помещаются в окне QTableView?

    @Mercury13
    Программист на «си с крестами» и не только
    Это на самом деле сложная задача, и я её решил вот так.
    QHeaderView* header = ui->tableView->verticalHeader();
    QWidget* viewport = header->viewport();
    int i1 = header->logicalIndexAt(0);
    int i2 = header->logicalIndexAt(viewport->height() - 1);
    if (i2 < 0)
        i2 = header->count() - 1;
    QString s = QString::number(i1) + " - " + QString::number(i2);
    ui->lbResult->setText(s);


    Если в очень упрощённом виде — то немного не так.
    return m_tableView->viewport()->height() / m_tableView->rowHeight(0);
    Ответ написан
    Комментировать
  • Приложения корректировки форматирования кода?

    @Mercury13
    Программист на «си с крестами» и не только
    Первое. Нужен сильно упрощённый синтаксический анализ, который делит код на директивы препроцессора, лексемы, операторы и комментарии, понимающий вложенность операторных скобок.
    Второе. Все эти лексемы выкидываем в выходной поток, добавляя незначащие символы по всоему усмотрению.
    Третье. Комментарии тоже придётся переформатировать, и с этим отдельный геморрой.
    Для Си — там есть ещё #define. Идеал — развернуть каждый #define, добавив спецсимволы «тут начало #define», «тут конец #define», форматнуть код, передвинуть левый спецсимвол как можно правее по незначащим символам (а правый — как можно левее), а потом опустить всё между спецсимволами, оставив только #define в том виде, как он был.
    Ответ написан
    Комментировать
  • Variadic template c++?

    @Mercury13
    Программист на «си с крестами» и не только
    Этот шаблон вычисляет при компиляции такое:
    rbv<false, false, true, true>() = 11002.

    И состоит из двух частей.
    1. Для одного параметра у нас напрямую написан шаблон.

    2. Для false, false, true, true — у нас используется второй шаблон: a=false, b=false, d = (true, true).
    И он равняется (rbv<false, true, true> << 1) + false.

    Чтобы вычислить новый rbv, снова работает второй шаблон: a = false, b = true, d = (true).
    И он равняется (rbv<true, true> << 1) + false.

    Для третьего rbv у нас a = true, b = true, d = ().
    Внимание, список d может быть и пусттым. Потому, чтобы не было конфликта с первым шаблоном, второй пишется для двух и более параметров.
    И третье наше значение равняется (rbv<true> << 1) + true.

    Вот тут работает первый шаблон и получается 112.
    Дальше уже можно вычислить все rbv по очереди и получить 11002.
    Ответ написан
    4 комментария