Задать вопрос
Ответы пользователя по тегу C++
  • Существует ли реализация J2ME для Java SE\С++?

    @Mercury13
    Программист на «си с крестами» и не только
    CLDC и MIDP — это всего лишь стандартные библиотеки Java ME. Первое — это штатные возможности процессора и JVM, более ограниченные, чем Java SE. Второе — доступ к аппаратуре телефона: LCDUI, MMAPI и прочее. Ещё одно отличие — т.н. преверификация классов (Java SE вычисляет информацию о классах сама, а Java ME с кастрированным загрузчиком — полагается на расчёт на настольном компьютере).

    Как они архитектурно реализованы, какой процент библиотек написан на Java и какой в машинном коде — программиста на Java ME совершенно не интересует (кроме случаев, когда на мобильнике какой-то класс глючит). На то он и ME, что даёт простой фреймворк для написания софта для мобильников.

    Какой-то эмулятор есть в Java ME SDK. Как его настроить под нужный мобильник, я не в курсе.
    Также есть MicroEmulator: https://code.google.com/archive/p/microemu/downloads . Если вы хотите быть такой элитой Java ME, что будете писать свои драйверы (или просто встроить поддержку ME куда-то в другую программу), думаю, что MicroEmulator — неплохой тестовый полигон. Обычный ME’шник драйверов не пишет, их пишут авторы прошивок мобильников.
    Ответ написан
  • Почему компилятор выдаёт ошибку?

    @Mercury13
    Программист на «си с крестами» и не только
    Это очень старый код, задолго до 1998 года, когда C++ стал стандартом.

    Сейчас (а вот не в курсе — в C++98 или C++03) огромное количество заголовков C++ объединили в стандартную библиотеку шаблонов (STL). Так что потребуется слегка изменить код.

    1. Вместо <iostream.h> использовать <iostream>. <stdio.h>, в принципе, работает, но рекомендуется брать <cstdio>.
    2. Все функции находятся в пространстве имён std. То есть: std::cout, std::endl, и т.д. Либо, как предложил D' Normalization, using namespace std;.
    Ответ написан
    Комментировать
  • Как в c++ уменьшить память, зарезервированную под вектор?

    @Mercury13
    Программист на «си с крестами» и не только
    c++11 — shrink_to_fit.
    Ответ написан
    Комментировать
  • Наследование 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 элементов.
    Ответ написан
  • Указатели в 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 комментарий
  • Где и в каких случаях правильно использовать 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);
    Ответ написан
    Комментировать
  • Почему не компилируется код при подключении vector?

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

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

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

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

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

    @Mercury13
    Программист на «си с крестами» и не только
    Это системно-зависимая задача, и в Qt такое только частично. Под Windows она выполняется так.
    1. Получить путь к COMMAND.COM, считав переменную окружения COMSPEC. Для этого есть класс QProcessEnvorinment.
    2. Запустить программу (CreateProcess или ShellExecute) с командной строкой "/c filename parameters". В Qt есть объект QProcess, его работоспособность я не проверял.
    3. Если ещё и нужно куда-то передать результат выполнения — разбирайтесь с перенаправлением ввода-вывода функции CreateProcess. В QProcess, вероятно, перенаправление ввода-вывода тоже есть.
    Ответ написан
    Комментировать
  • Как затереть ссылку возврата?

    @Mercury13
    Программист на «си с крестами» и не только
    Для чего это нужно? А для того, чтобы вы знали, как хакеры вас ломают. Простейший способ для этого — устроить переполнение буфера.
    void foo()
    {
      void* a[1];
      a[1] = (void*)&bar;
    }

    Может быть, придётся подменить не a[1], а a[2] или a[3].
    Если так поступить, bar-то будет вызван, но по выходу из него, скорее всего, программа упадёт. Как сделать, чтобы не упала — оставлю домашним заданием. Высший пилотаж — завести в main() пару переменных, а потом через std::cout показать: вот они, целые и невредимые (компилируйте без оптимизации, макс. оптимизация может их просто заменить константами). Но тут уже придётся знать соглашение вызова и читать дизассемблерный листинг: от этого зависит, как вернуть стек в подходящее состояние.

    UPD. Простите за моё незнание синтаксиса Си.
    Ответ написан
    5 комментариев
  • Как подключить libcurl к Qt?

    @Mercury13
    Программист на «си с крестами» и не только
    Подключать надо libcurldll.a в таком виде.
    -LC:\Qt\curl-7.49.0-win32-mingw\lib -lcurldll

    Вот кусок, взятый из реального проекта.
    win32|win64: LIBS += -lws2_32 -lshlwapi -lodbc32 -lpsapi -lcomdlg32 \
                         -L$$PWD/../../Common/cURL/lib/ -lcurldll -lole32 \
                         -loleaut32


    Кроме того, тебе не хватает OpenSSL — найди libeay32.dll и ssleay32.dll, лучше скомпилированные старой версией MSVC и не требующие новых runtime’ов, которые есть не везде. Ах да, есть версии libcurl, которые скомпилированы без SSL — им этого, разумеется, не нужно.

    Подожди, сейчас посмотрю, что будет, если вкомпилировать в программу библиотеку cURL статически, без DLL.

    UPD. Попробовал. Почти работает, но надо разобраться, как подключить winsock и OpenSSL — раньше-то ими занимался тот, кто компилирует DLL, а сейчас это будет моя забота.
    Ответ написан
  • Как поместить "нетривиальный" объект в стуктуру?

    @Mercury13
    Программист на «си с крестами» и не только
    Одно из полей (в данном случае data в реализации item<Edge>) не имеет конструктора по умолчанию. Есть три пути.

    РАЗ. Придумать, как сделать, чтобы конструктор всё-таки был.
    class Edge : public EdgeBase
    {
    public:
      Edge (Point* firstPoint, Point* secondPoint) { init(firstPoint, secondPoint); }
      Edge () { init(NULL, NULL); }
      void init (Point* firstPoint, Point* secondPoint)
      {
        this->firstPoint = firstPoint;
        this->secondPoint = secondPoint;
      }
    private:
      Point* firstPoint;
      Point* secondPoint;
    };


    ДВА. Если объект копируется/переносится, можно воспользоваться такой штукой. С вашего позволения, упрощу задачу и вместо Edge заведу другой класс — ImmutableInt. Правда, этот код — попытка совместить ежа с ужом (непонятно, какую концепцию должен поддерживать Payload), но, тем не менее, работает.
    #include <iostream>
    
    class ImmutableInt
    {
    public:
        explicit ImmutableInt(int x) : fData(x) {}
        int data() const { return fData; }
    private:
        int fData;
    };
    
    template <class Payload>
    class ListItem
    {
    public:
        Payload payload;
        ListItem* next;
    
        ListItem() : next(NULL) {}
        ListItem(const Payload& x) : payload(x), next(NULL) {}
    };
    
    // Так писать нельзя — эта конструкция расшаблонивает все функции,
    // а конструктора по умолчанию как не было, так и нет!
    //template class ListItem<ImmutableInt>;
    
    int main()
    {
        ListItem<ImmutableInt> li(ImmutableInt(42));
        std::cout << li.payload.data() << std::endl;
        return 0;
    }


    ТРИ. Воспользоваться переменными шаблонами (variadic templates) C++11.
    #include <iostream>
    
    class ImmutableInt
    {
    public:
        explicit ImmutableInt(int x) : fData(x) {}
        int data() const { return fData; }
    private:
        int fData;
    };
    
    template <class Payload>
    class ListItem
    {
    public:
        Payload payload;
        ListItem* next = nullptr;
    
        template<class... Args>ListItem(Args... args) : payload(args...) {}
    };
    
    int main()
    {
        ListItem<ImmutableInt> li(42);
        std::cout << li.payload.data() << std::endl;
        return 0;
    }


    P.S. Хотя ImmutableInt — семантически тот же int и теоретически explicit не надо, всё-таки отметил — просто чтобы показать, что во втором случае мы передаём параметром ImmutableInt<42>, а в третьем — 42.

    P.P.S. Я упомянул слово «концепция». Это набор требований к типу. Что-то типа интерфейса — но, во-первых, никак не связано с ООП и его динамическим полиморфизмом, и, во-вторых, не столь жёсткое: как ты интерфейсом из Java наладишь концепцию «есть конструктор копирования» или «может делить себя на число и что-то выходит»? Синтаксическая поддержка концепций откладывается на C++17, но уже в C++03 было несколько концепций: InputIterator, DefaultConstructible, CopyAssignable и другие. А пока… концепция не поддерживается — ошибка компиляции где-то в страшенном стандартном хедере.

    P.P.P.S. Написав код
    template<typename type_t>
    struct item
    {
      item* next;
      type_t data;
    };

    вы автоматически потребовали от type_t концепцию DefaultConstructible (есть конструктор по умолчанию)
    Ответ написан
    1 комментарий
  • Как программно скачать несколько файлов с сайта?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Заполучить принцип, по которому строятся ссылки. Возможно, для этого придётся разбирать код самого сайта.
    2. Использовать любую библиотеку HTTP: Indy (Delphi), cURL (DLL с большим количеством привязок) или что-нибудь другое. С другими я, к сожалению, не работал. Ну или просто запускать подходящий EXE-загрузчик (wget, curl…).
    3. Обойти анти-DDoS’овские меры. Многие сети раздачи контента проверяют, похож ли клиент на легитимный браузер — наш бот должен все эти меры обойти.

    Знаю, что слабость последних версий Indy — ориентация на .NET и вытекающие оттуда ограничения; также Indy «слишком вумный» и сложные REST-службы не работают, так как строишь тело, вычисляешь имитовставку — а служба говорит, что они друг другу не соответствуют; видимо, Indy что-то подстроил. Кстати, когда я понял, что запросы без тела работают, а с телом — ни в какую, первым тестом стал curl.exe, и только потом подключил libcurl через собственную Delphi-привязку.

    Слабость cURL — тонкости протоколов (скажем, заголовки и кодировки) остаются за прикладными программистом; ориентирован на FILE* и на всех языках, кроме Си, запись в файл слегка затруднена; ориентирован на vararg и если работать без типобезопасной обёртки, надо быть предельно осторожным.
    Ответ написан
    Комментировать
  • Как изменять значения переменных другого класса в C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Не буду говорить о качестве кода, const-корректности и прочей бяке. Конкретная ваша ошибка
    int& operator [](int i) // именно ссылка!

    У вас возвращается значение — временный объект, которому, разумеется, невозможно присвоить что бы то ни было.
    Ответ написан
  • Как удалить элемент из вектора, а затем добавить несколько новых?

    @Mercury13
    Программист на «си с крестами» и не только
    У вас могут быть две проблемы.
    1. Неверно написана операция «присвоить» или «переместить».
    2. Забыл, что в std::vector при операции «добавить» или «удалить» возможно физическое перемещение объекта и ссылки на него больше недействительны.

    Ну и IsEnded лучше писать вот так.
    bool IsEnded(const Query &aVar) { return (aVar.id == NO_ID); }
    Ответ написан
    2 комментария
  • Что будет содержать абстрактный класс?

    @Mercury13
    Программист на «си с крестами» и не только
    Вариант один вы предложили. Всё пишу на C++03, без шаблонов. C++11 и шаблоны, разумеется, дадут больше вариантов.
    class Object {
    public:
        virtual ~Object() {}
    };
    
    class List {    // interface
    protected:
        virtual Object& getAt(size_t i) = 0;
    public:
        virtual size_t size() const = 0;
        inline Object& at(size_t i) { return getAt(i); }
        inline const Object& at(size_t i) const
            { return const_cast<List*>(this)->getAt(i); }
        virtual ~List() {}
    };

    Вариант 2. С ним пользователю не так просто, но если к нему ещё добавить лямбда-функции C++11 — вообще бомба будет!
    class ListCallback {    // interface
    public:
        virtual void act(size_t index, Object& object) = 0;
        virtual ~ListCallback() {}
    };
    
    class ListConstCallback {   // interface
    public:
        virtual void act(size_t index, const Object& object) = 0;
        virtual ~ListConstCallback() {}
    };
    
    class List2 {   // interface
    public:
        virtual size_t size() const = 0;
        virtual void enumerate(ListCallback& body) = 0;
        virtual void enumerate(ListConstCallback& body) const = 0;
    };

    Например, для динамического массива, у которого быстрый доступ по номеру, будет такое тело
    void DynArray::enumerate(ListConstCallback& body) const {
       size_t sz = size();
       for (size_t i = 0; i < sz; ++i)
           body(i, operator[](i));
    }

    Разумеется, если вы нагрузкой сделаете не абстрактный Object, а что-то окончательное, dynamic_cast не нужен будет.

    Вариант 3 принят в Java. Один недостаток — мого кода писать для const-корректности, так что с вашего позволения опущу.
    class VirtualListIterator { // interface
    public:
        virtual bool next() = 0;
        virtual Object& value() = 0;
        virtual ~VirtualListIterator() {}
    };
    
    class ListIterator {   // Назван так для красоты, по сути это умный указатель
    private:
        VirtualListIterator* ptr;
        // Запретим копирование и op=, но при желании можно реализовать и их
        ListIterator(ListIterator&) {}
        void operator=(const ListIterator&) {}
    public:
        ListIterator() : ptr(NULL) {}
        ListIterator(VirtualListIterator* value) : ptr(value) {}
        ~ListIterator() { delete ptr; }
        bool next() { return ptr->next(); }
        Object* operator->() const { return &ptr->value(); }
        Object& operator*() const { return ptr->value(); }
    };
    
    class List3 {   // interface
    public:
        virtual size_t size() const = 0;
        virtual VirtualListIterator* enumerate() = 0;
    };
    
    class Number : public Object {
    public:
        int value;
    };
    
    // И пользоваться этим так...
    void doSmth(List3& aList) {
        ListIterator it(aList.enumerate());
        while (it.next()) {
            std::cout << dynamic_cast<Number&>(*it).value << std::endl;
        }
    }


    Во всех трёх вариантах не забывайте: если нагрузка — не что-то окончательное, а абстрактный класс, элементы придётся хранить по указателю и вручную уничтожать.

    Да, и из вас будет хороший инженер, если вы сразу же задумываетесь о производительности.
    Ответ написан
    Комментировать
  • Как создать динамический массив из объектов класса?

    @Mercury13
    Программист на «си с крестами» и не только
    Операция присваивания или перемещения есть? Пускай даже созданная автоматически? Если есть — вот, смотрите.
    #include <iostream>
    #include <vector>
    
    class Test {
      int k;
    public:
      Test(int _i) {k = _i; }
    
      void put_k(int i) {k = i; }
      int get_k() {return k; }
    };
    
    
    struct TestWrapper {
        Test payload;
        TestWrapper() : payload(0) {}
        TestWrapper(int i) : payload(i) {}
        TestWrapper(const Test& i) : payload(i) {}
    };
    
    int main()
    {
        Test test(10);
        std::vector<TestWrapper> v;
        v.push_back(test);
        std::cout << v[0].payload.get_k() << std::endl;
        return 0;
    }


    Если нет — тогда динамический массив так просто работать не может (фишка динамического массива — заводить новый массив и копировать информацию из старого). Только использованием умных указателей.
    #include <iostream>
    #include <vector>
    #include <memory>
    
    
    class Test {
      int k;
    public:
      Test(int _i) {k = _i; }
      Test& operator=(const Test&) = delete;
      Test& operator=(Test&&) = delete;
    
      void put_k(int i) {k = i; }
      int get_k() {return k; }
    };
    
    
    int main()
    {
        std::vector<std::unique_ptr<Test>> v;
        v.push_back(std::unique_ptr<Test>(new Test(10)));
        std::cout << v[0]->get_k() << std::endl;
        return 0;
    }
    Ответ написан
  • Передача узла дерева?

    @Mercury13
    Программист на «си с крестами» и не только
    По сути. Вы забыли порядок исполнения операций.
    (*root)->next.push_back(node);

    Чем ещё можно улучшить код…
    Зачем вам указатель на указатель? Как массив указателей? Как «либо ссылка на указатель, либо ничего»? По видимому, ни то, ни другое, указатель, по сути передаётся по значению — так что стоило бы функцию переделать как…
    bool Syntax::On_BG(Node * root)
    или даже
    bool Syntax::On_BG(Node & root)

    PS. И да, указатель передаётся по значению, но то, на что он указывает, не исчезнет с выходом из функции.
    Ответ написан
  • Qt, Время собирать "камни" или как получить Release?

    @Mercury13
    Программист на «си с крестами» и не только
    «can't find -lQSerialPort» — это значит, не в инклудах дело, а в .lib или в .a (зависит от компилятора). Ищи, как указать путь к этому файлу. И почему в отладке работало? — там что, этот путь указан?
    Ответ написан
    4 комментария