Задать вопрос
  • Наследование C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Private и protected — это когда объект скрывает, что унаследован от студента. Снаружи не виден ни факт наследования, ни отцовские поля.
    class Father {};
    class Son : private Father {};
    
    int main()
    {
        Son son;
        Father& q = son;
    }

    error: 'Father' is an inaccessible base of 'Son'

    Private и protected — скорее «хаки» и пользоваться ими не рекомендуется. Хотя, разумеется, пользуются, чтобы упростить себе жизнь. Я вижу два назначения: 1) хорошая основа для совершенно постороннего класса; 2) реализация интерфейса, которая нужна только внутри.

    Вот пример второго. Объект FileWriter реализует интерфейс Callback для своих внутренних нужд.
    #include <iostream>
    
    class Callback {
    public:
        virtual void act(int x) = 0;
    };
    
    void generateFibonacci(int n, Callback& callback) {
        int x1 = 0, x2 = 1;
        for (int i = 0; i < n; ++i) {
            callback.act(x2);
            int x3 = x1 + x2;
            x1 = x2;
            x2 = x3;
        }
    }
    
    class FileWriter : private Callback {
    public:
        FileWriter(std::ostream& aOs, int aN) : os(aOs), n(aN) {}
        void run() { generateFibonacci(n, *this); }
    private:
        std::ostream& os;
        const int n;
        void act(int x) override { os << x << std::endl; }
    };
    using namespace std;
    
    int main()
    {
        FileWriter wri(std::cerr, 10);
        wri.run();
    }

    А если реальная жизнь — то объект может быть одновременно QDialog (диалоговое окно) и QAbstractItemModel (модель данных для какой-нибудь таблицы, лежащей на этом окошке). Хотя, повторяю, это скорее хак.

    P.S. В Delphi и Java всё наследование публичное, и если нужно скрытно реализовать какой-то интерфейс или задействовать удобный класс — то только скрытым полем. Так, как в комментариях.

    P.P.S. Пример первого. Какой-нибудь Array2d скрыто наследуется от Array1d, потому что у него совершенно другой интерфейс. У Array1d — alloc(n) и operator()(i), у Array2d — alloc(m, n) и operator()(i, j). А Array1d — неплохая штука, чтобы управляться блоком памяти длиной m×n элементов.
    Ответ написан
  • Как убрать раскладку клавиатуры на мобильном устройстве?

    @Mercury13
    Программист на «си с крестами» и не только
    Так работает браузер: ставишь курсор в поле — появляется клавиатура. И ничего с этим не сделаешь, надо искать обходы. Вот на выбор несколько вариантов.
    1. Сделать поле невидимым, как минимум на мобильных платформах.
    2. Сделать так, чтобы выбор даты не требовал постановки курсора в поле.
    3. В HTML5 есть несколько специализированных полей ввода специально для дат. WebRef говорит, что работает с большими ограничениями и потому желательно всё-таки сделать календарь на JS — но они есть.

    ЗЫ. Проверил специализированные элементы управления на мобильных Chrome и Firefox, вышло вот что.
    Number: Cr cool, Fx заглючивает тултип, если цифра не в диапазоне
    Date: Cr cool, Fx вылет
    Color: Cr работает (хотя можно наставить побольше предопределённых цветов), Fx выбор из десятка цветов
    Range: оба cool
    Month: Cr cool, Fx вылет
    Week: Cr недостаточный интерфейс, Fx вылет
    Time: оба cool
    Datetime: Cr не работает, Fx вылет
    Datetime-local: Cr недостаточный интерфейс, Fx вылет
    Search: ничем, кроме вида кнопки OK, не отличаются
    Tel: оба cool
    Url: оба cool
    Ответ написан
    Комментировать
  • А допустимо ли делать пхп страницу на инклюдах?

    @Mercury13
    Программист на «си с крестами» и не только
    Лучше вместо include использовать require.
    Хорошее дело, если нужно быстро придумать недо-CMS.
    Ответ написан
    Комментировать
  • Почему такая разница в производительности SQLite в PHP и Delphi?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Есть подозрение, что вы по какой-то причине в C++-версии не предкомпилируете запросы. Запрос компилируется каждый раз, когда вы его исполняете. Хотя это зависит от обёртки — простыми Си’шными функциями работать с SQLite ой как тяжко, все используют обёртки.
    2. Если компилируете SQLite классическим компилятором Embarcadero — он в несколько раз медленнее других. Хотя разницу в несколько порядков давать не может. Кстати, столь большие Си-файлы быстро заглючивают Embarcadero, и лучше SQLite отправить в статическую или динамическую библиотеку.
    Ответ написан
    1 комментарий
  • Как сделать, чтобы аппаратная клавиатура Android печатала на русском?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    О, GK обновили, всё работает! Мой багрепорт подействовал.

    А временное решение — накопать любую подходящую клавиатуру. Я использовал SwiftKey.
    Ответ написан
  • Как создать калькулятор (аналоги строительных)?

    @Mercury13
    Программист на «си с крестами» и не только
    Самый лучший инструмент для прототипов — Excel. Или любая другая понравившаяся таблица, например, LibreCalc.
    Для Android — Android Development Studio, понятное дело.
    Настольную программу можно написать даже на JavaScript. Если же нужен EXE — что угодно, на чём умеешь программировать. Я бы взял визуальную систему наподобие Delphi, Qt или WinForms.
    Ответ написан
    Комментировать
  • Как исправить ошибку "Array keys must be CURLOPT constants or equivalent integer values"?

    @Mercury13
    Программист на «си с крестами» и не только
    Скорее всего, староват PHP. Константа привязки (не cURL!) CURLOPT_SAFE_UPLOAD появилась в PHP 5.5.0.

    Что означает константа привязки? Вот я написал обёртку для cURL под C++ и сделал функцию switchRecvToString — чтобы переключить приём с консоли на std::string. Это не функция cURL (он вообще на чистом Си написан), это я сделал в привязке к C++. Так же и тут — на curl.haxx.se этой опции нет, это опция привязки cURL к PHP.
    Ответ написан
  • Указатели в C++: что такое "x{"?

    @Mercury13
    Программист на «си с крестами» и не только
    Дело в том, что для char* работает особый механизм вывода в поток. Этот указатель воспринимается не как адрес, а как строка Си. Первым символом строки будет, разумеется, R. А дальше — идёт по памяти и выводит все байты подряд, пока не обнаружит 0.

    Поскольку после char (1 байт) идёт char* (8 байтов), нам придётся создать семь байтов выравнивания (судя по длине указателя, мы на x64). В этих семи байтах и обнаружились фигурная скобка, ноль и непонятно что.

    Поставьте вместо char int — будет всё, как вы думали. Указатель int* выводится без всяких интерпретаций.
    Ответ написан
    2 комментария
  • Как правильно создать локальную копию std::wstring?

    @Mercury13
    Программист на «си с крестами» и не только
    void doSomething(std::wstring* s)
    {
       std::wstring temp = *s;
    }
    Ответ написан
    1 комментарий
  • Если в языке есть циклы и условия это потому, что процессор всё это непосредственно поддерживает?

    @Mercury13
    Программист на «си с крестами» и не только
    Циклы и условия — это для того, чтобы язык был полным по Тьюрингу (т.е. был — на бесконечной памяти, разумеется — эквивалентен машине Тьюринга). На языке процессора циклы и условия выглядят совсем не так (там, по сути, куча GOTO и IF GOTO), но машинный код тоже полон по Тьюрингу.

    Впрочем, есть вещи, которые поддерживаются языком именно потому, что процессор их поддерживает. Обычно хватает поддержки на уровне библиотек: атомарные операции, аппаратное шифрование… Но есть и вещи, вошедшие в собственно язык. Вот несколько штук.
    • Нуль-терминированные строки, насколько мне известно, включили в Си потому, что на том PDP это было быстро.
    • Большинство языков, деля с остатком отрицательные числа, говорят, что округление идёт к нулю (знак остатка = знаку делимого) — потому что так работает большинство процессоров.
    • Модель памяти Java говорит: нет невесть откуда взявшихся значений (другими словами, если мы считали 1234 — значит, до этого кто-то его туда записал), за исключением не-volatile long и double. На 16-битный процессор многопоточную Яву ставить бессмысленно, а 32-битный — это уже дело.

    Вызовы функций — с ними всё наоборот. Как только выяснилось, что это хорошая штука, для них сделали аппаратную поддержку. А так — для вызова функций (в удобоваримом для компилятора виде, с хорошо стандартизованными соглашениями вызова) хватает косвенной адресации и пары лишних регистров.
    Ответ написан
    Комментировать
  • Где и в каких случаях правильно использовать extern?

    @Mercury13
    Программист на «си с крестами» и не только
    Назначение extern единственное. Мы говорим, что этой переменной нет в данной единице компиляции, но не надо переживать, она есть в другой и компоновщик её подкомпонует.

    По факту является extern’ом static-поле класса. Это решение принято Строуструпом по простой причине: определение класса может промелькнуть несколько раз в разных единицах компиляции, а определение переменной должно быть одно на программу.

    Если ваш код не работает без extern — это значит, что где-то нашлась глобальная переменная по имени client, и для корректной работы вебмастера потребовалось обращаться к этому нашему клиенту. По факту — очень навороченный способ создать static-поле.

    Таким образом, у вас три варианта.

    1. Если Ethernet-клиент один на всех вебмастеров, вам нужно static-поле.
    // HEADER
    class WebMaster {
    public:
        WebMaster();
        bool connect_open();
    private:
        static EthernetClient client;
    }
    
    // CPP
    EthernetClient WebMaster::client;


    Впрочем, этот вариант крайне маловероятен.

    2. Скорее всего, у вас один вебмастер — один клиент и, вероятно, вам нужно обычное нестатическое поле.
    class WebMaster {
    public:
        WebMaster();
        bool connect_open();
    private:
        EthernetClient client;
    }


    3. Если у нас приходится привязывать мастеров к клиентам, приходится использовать указатели и ссылки. В простейшем виде…
    // HEADER
    class WebMaster {
    public:
        WebMaster(EthernetClient& aClient);
        bool connect_open();
    private:
        EthernetClient& client;
    }
    
    // CPP
    WebMaster::WebMaster(EthernetClient& aClient) : client(aClient) {}
    
    ...
    EthernetClient client;
    WebMaster webmaster(client);
    Ответ написан
    Комментировать
  • Как вывести таблицу в таком формате?

    @Mercury13
    Программист на «си с крестами» и не только
    Храните так, как подсказывает специфика ваших данных. Маловероятно, что это у вас нечто на все случаи жизни.

    Для вывода подходит, например, KGrid.
    Ответ написан
    Комментировать
  • Как реализовать обратную совместимость пользовательских данных в программе?

    @Mercury13
    Программист на «си с крестами» и не только
    Проще всего это сделать в XML. Тогда мы легко можем добавлять новые теги и игнорировать то, что в XML не входит.

    Двоичный файл надо делать на манер XML — в виде иерархической конструкции из коротеньких потоков. Самое сложное — чтобы по этому двоичному файлу не надо было бегать туда-сюда, как по гоночному треку. Для этого на каждом из уровней иерархии бывает одно из двух.
    1. Запросить некую последовательность кодов, а затем спрашивать: есть этот код? А есть этот? Что-то типа (для простоты пишу как на C++)…
    BlockReader blk;
    int order1[] = { opHeader, opSettings, dirData };
    BlockOrder order(blk, order1);
    
    order.require(opHeader);
    // считать заголовок
    author = blk.readString();
    
    if (order.get(opSettings) {
      // считать настройки
    }
    
    order.require(dirData);
    blk.enterDir();
      // считать данные таким же образом — там может быть свой BlockOrder
    blk.leaveDir();


    Да, для чего мы запрашиваем порядок блоков дважды?
    Первый раз — вот для чего. Представим себе устаревший файл, в котором нет блока настроек. Мы считываем заголовок, видим вместо блока настроек каталог с данными, и сразу вопрос: тут что-то пропущено или что-то лишнее?
    Второй раз — для наглядности (код комментирует сам себя) и защиты от ошибок, когда заявленный в начале порядок не совпадает с реальным.

    2. Просто считываем блоки по одному и интерпретируем. Обычно это бывает во всяких коллекциях.
    while (blk.getBlock()) {
      switch (blk.opcode) {
      case dirTiledLevel:
         // считать плиточный уровень
      case dirGraphicLevel:
         // считать уровень с фоном — цельной картинкой
      }
    }

    Запрещается смешивать упорядоченное с коллекциями.

    Можно также в заголовке каждого блока сделать бит: Essential. Старая версия, наткнувшись на такой блок и не считав ни байта (или наткнувшись на каталог и не войдя), выводит ошибку: версия явно новее, считать невозможно. Это бывает важно, когда в файле есть перекрёстные ссылки.

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

    Далее. В заголовке можно сохранить поля «SavedWithVersion», «MinRequiredVersion», «MinFullySupportingVersion».
    Добавляем новый блок (или новое поле в имеющийся блок) — поднимаем MinFullySupportingVersion до текущей. Изменяем структуру так, что ломаем совместимость — поднимаем MinRequiredVersion.

    То, что версия слегка устарела, можно ловить и по косвенным признакам — какой-то блок считан не полностью, в какой-то каталог не вошли. У блока/каталога может быть флаг Compatibility — их проверять не надо. И наоборот — если важный блок отмечен как Compatibility, тоже версия устарела. Ясное дело, флаги Essential и Compatibility не могут попадаться вместе.

    Как это делать, если формат сохранения — база данных (например, SQLite), я не в курсе.

    А вот сохранение в устаревший формат, когда структуры данных ушли далеко вперёд, придётся налаживать руками. Можно ли в принципе, как преобразовать в старый формат, и т.д.
    Ответ написан
    Комментировать
  • Как передать музыку с сайта на микрофон?

    @Mercury13
    Программист на «си с крестами» и не только
    Вам нужно записать звук, идущий с сайта?
    Гуглить надо «audio loopback [ваша ОС]».
    У меня, допустим, сработало вот это.
    manual.audacityteam.org/man/tutorial_recording_com...
    Трещит страшно (у меня в «продвинутой» звуковой каналы переключаются тёплыми электромагнитными релюшками), но работает.
    Работает ли Protected Media Path и как он поведёт себя на закопирайченных данных — шут его знает. Проверял на банальном YouTube, там никакой защиты от копирования нет.

    Если же хотите не просто записать звук, а средствами JavaScript… Гуглите «javascript sound recording». Правда, на JS нет автоматического выбора, какое устройство считать микрофоном — так что пользователь должен убедиться, что в драйверах есть loopback-устройство, включить звукозапись и в качестве микрофона взять loopback (у меня оно «из коробки» и называется Stereo Mix). Без вмешательства пользователя, получается, никак. Сделано это специально: устройств звукозаписи бывает много, и одни задачи, например, выполняются студийным микрофоном с USB-платой, другие — наушниками с микрофоном, третьи — вебкой. К тому же окружающий звук — это очень-очень чувствительная информация, и без согласия пользователя писать что бы то ни было недопустимо.
    У меня сработали не все звукозаписывалки, вот эта, например, сработала (одна вкладка «лисички» проигрывала, вторая писала): https://p5js.org/examples/examples/Sound__Record_S...
    Повторяю, пользователь должен в качестве микрофона выбрать loopback-устройство, и без этого никак! Устройство должно существовать, и пользователь его должен выбрать.

    А если воткнуть колонки в порт микрофона и выдать на них звук — надо разбираться с аудиоустройствами и аудиодрайверами, и JS этого точно не может.
    Ответ написан
    Комментировать
  • Как действует предупреждение «Suspicious names combination» в NetBeans?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Suspicious names combination прост и туп: x с width, y с height. Даже если в одном месте x или width, а рядом ни того, ни другого — уже предупреждение. Причём x и y находит в довольно-таки экзотических местах. И energy ему не понравился именно буквой y.
    Ответ написан
    Комментировать
  • Qt: как перехватить событие «курсор мыши встал на линейку прокрутки»?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    У большинства компонентов можно заменять линейки прокрутки на свои. С ними-то можно делать что угодно.
    Ответ написан
    Комментировать
  • QAbstractTableModel: почему доступна только одна строчка и остальные серые?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Моё решение.
    У QModelIndex есть ссылка на модель! Поэтому…

    1. index должен создавать СВОЙ индекс.
    return slave.index(row - 1, column, parent);
    Неверно, надо создавать свой индекс. И вообще, если модель табличная, index будет тривиальным и его можно взять у QAbstractTableModel.

    2. А вот data — именно data, а не index — должен просить slave создать новый индекс.
    return slave.data(index, role);
    Неверно, пусть сначала slave преобразует координаты в свой индекс, а затем обратимся с этим индексом к его data.
    Ответ написан
    Комментировать
  • Почему не компилируется код при подключении vector?

    @Mercury13
    Программист на «си с крестами» и не только
    Вероятнее всего, где-то в предыдущем хедере — в том, что находится перед нашим <vector> — что-то не закрыто (пространство имён, функция и т.д.)

    UPD2. Получилось повторить ошибку таким кодом.
    void x() {
    #include <vector>
    };

    Если вместо функции x() взять класс или пространство имён, ошибка будет другая.
    Так что 90%, что вы не сбалансировали скобки в функции.
    Ответ написан
    2 комментария
  • Какую выбрать мышку среди данных моделей?

    @Mercury13
    Программист на «си с крестами» и не только
    Попробуй ответить на такие вопросы.
    1. Есть ли критичные задачи, к коим относятся динамичные игры, графика, САПР?
    2. Насколько нравится (или не нравится) «повышенная точность курсора» (на деле — ускорение мыши, нелинейная зависимость между скоростью мыши и скоростью курсора)?
    3. Какой монитор?
    4. Есть ли стеснённое пространство?
    5. Есть ли другие специальные требования? Например, мне нужны кнопки «вперёд-назад» и прокрутка удерживанием. Кому-то надо все настройки записывать в мышь и переносить на другой компьютер.
    По опыту. На обычном ноутбуке на 1400px годится практически любая мышь на 800+ dpi. 1680px — ищи 800…1000 dpi, в стёснённом пространстве могут потребоваться 1200. FullHD — ищи 1000…1200 dpi, в стеснённом пространстве — настраиваемая скорость. Правда, на HiDPI пропускания пикселей (чем, по сути, и будет повышенная чувствительность, установленная в средствах Windows) не настолько критичны. «Повышенная точность» выключена.

    ЗЫ. Вот и нашлась специальная задача. Перед нами мак, и нужно смотреть, есть ли драйверы для спец. кнопок под него.
    • Marathon — 1000 dpi. Нужно смотреть, хватает ли чувствительности, по руке ли, и т.д., но в целом мышь как мышь. Ещё моё ИМХО — крышка может разболтаться и мешать мышить. Как передвижная — из-за крышки непригодна абсолютно.
    • MX. Под одной позицией смешали MX и MX2. Вторая огонь, но надо проверять чисто программные фишки. Если после выключения возвращает эту самую чувствительность назад на некомфортный уровень — не брать. Первая дешевле, информации по ней не вижу.
    • Apple. Главное нарекание — не всякому по руке. Плюс ненадёжно регистрирует правый щелчок.
    • G700s. Слишком дрянные отзывы, особенно на аккумулятор и сборку.

    И ещё. Если ешь на рабочем месте, откажись от резиновых вставок, они жутко собирают крошки. А если нет — они сказочно хороши на ощупь.
    Ответ написан
    2 комментария
  • Почему программисты не любят возврат константных ссылок в C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Я думаю, причина единственная — не надо смотреть на время жизни объекта.
    Если же нужно сэкономить, в возвращаемый результат встраивают умный указатель. Так работают, например, QString и QDatabase.

    А вот в каких-нибудь низкоуровневых векторах — вполне себе константные ссылки.
    const T &QVector::at(int i) const
    Ответ написан
    Комментировать