Ответы пользователя по тегу C++
  • Переопределить operator() для получения доступа к члену класса?

    @Mercury13
    Программист на «си с крестами» и не только
    class Window{
    public:
      Graphics& operator * () const { return *g; }
      Graphics* operator -> () const { return g; }
    private:
      Graphics *g;
    }
    
    ...
    
    window->Clear(Color::White);
    Ответ написан
    2 комментария
  • Как написать функцию которая может не вернуть значение?

    @Mercury13
    Программист на «си с крестами» и не только
    Object* find (const Object& o)
    {
        /* Поиск, если нашли */
       return link;
       /* Если не нашли? */
       return NULL; // Теперь можно
    }
    Ответ написан
    5 комментариев
  • Как использовать "гибкость" двумерного массива, перед одномерным?

    @Mercury13
    Программист на «си с крестами» и не только
    Итак, перед нами задача: сделать динамический массив «умных указателей единоличного владения». Умный указатель единоличного владения (std::unique_ptr из C++11) — это указатель, который самолично владеет выделенной памятью; при исчезновении указателя исчезает и память.

    Раз мы только учимся, мы не будем влезать в самописные шаблоны C++, готовые шаблоны STL (кроме algorithm и string) и новый, но уже реализованный во всех компиляторах стандарт C++11. Это довольно серьёзное ограничение; если его снять, можно серьёзно упростить себе жизнь. А для этого мы отделим структуру данных от жизненных объектов и реализуем объект StudentList. Пишу с листа, возможны ошибки.

    Да, и без C++11 умный указатель единоличного владения реализовать довольно тяжело — поэтому структуру данных будем делать «монолитно», без разделения на умный указатель и динамический массив.

    #include <algorithm>
    
    class StudentList
    {
    public:
      StudentList();
      ~StudentList();
      Student& add();   // добавить пустого студента и выдать ссылку на новенького
      size_t size() const { return fSize; }
      Student& operator[](size_t i) { return *fData[i]; }   // можно также наладить проверку диапазона — сделай это сам…
      const Student& operator[](size_t i) const { return *fData[i]; }
      void clear();
    private:
      typedef Student* PStudent;
      PStudent* fData;
      size_t fSize, fCapacity;   // реальное кол-во студентов и на сколько студентов у нас заведено памяти.
                            // Указатели [fSize..fCapacity) резервные, их значение не определено и высвобождать
                            // их не надо.
      enum { BLOCK_SIZE = 16; };
      StudentList(const StudentList&) {}   // копирование запрещаем, хочешь — реализуй сам и вынеси в public
      StudentList& operator=(const StudentList&) { return *this; }  // аналогично
    };
    
    StudentList::StudentList(); : fData(NULL), fSize(0), fCapacity(0) {}
    
    Student& StudentList::add()
    {
      // Убедиться, что массива хватает; если нет — расширить
      if (fSize >= fCapacity) {
        size_t newCapacity = fCapacity + BLOCK_SIZE;
        PStudent* newData = new PStudent[newCapacity];
        std::copy(fData, fData + fSize, newData);
        delete[] fData;
        fData = newData;
        fCapacity = newCapacity;
      }
      // Завести нового студента
      Student* r = new Student;
      fData[fSize++] = r;
      return *r;
    }
    
    void StudentList::clear()
    {
       for (size_t i = 0; i < fSize; ++i)
         delete fData[i];
       delete[] fData;
       fData = NULL;
       fSize = 0;
       fCapacity = 0;
    }
    
    StudentList::~StudentList()
    {
       clear();
    }


    Удаление и прочее сам наладишь?

    А группа будет пользоваться нашим списком.

    #include <string>
    
    class AcademyGroup
    {
    public:
       std::string name;
       StudentList students;  // при желании можно заинкапсулировать и его.
    };


    Это перед нами, правда, не двухмерный массив, как я уже сказал. Массив, хоть и Student**, но одномерный; каждый элемент массива — умный указатель единоличного владения. Если бы мы писали на STL C++11, это был бы std::vector<std::unique_ptr<Student>>.

    Кроме УУЕВ, существует также умный указатель совместного владения std::shared_ptr.

    Можно сделать второй вариант — массив из одномерных массивов. Если он заполнился — заводим ещё один массивчик. Пишется немного сложнее, особенно если не пользоваться STL. На STL — std::deque<Student>.
    Ответ написан
    6 комментариев
  • Как поймать в GDB исключение, вызванное из basic_string(const charT*)?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Нашёл.
    Подключить статический libc++ (-static-libstdc++), тогда всё будет.
    Ответ написан
    Комментировать
  • Почему this NULL в istream_iterator?

    @Mercury13
    Программист на «си с крестами» и не только
    Операторы перегружены правильно.

    А вот и нет. Ваша ошибка
    std::istream& operator>>(std::istream& s, Pnt& p)   // убрать const!

    Не обязательно, но можно.
    explicit Pnt(int s) {…} // добавить explicit!
    Что получается? Мы пытаемся считать в неизменную p.a. Прямое s >> p.a; не подходит — поле-то неизменное. И тут, как ни странно, находится цепочка: создать временный Pnt и снова вызвать саму себя!

    Добавить explicit: запрещаем вызывать этот конструктор неявно.
    Убрать const: расфиксировать p.a.

    Также у вас ошибка в перегрузке операции «присвоить».
    Pnt& operator=(const int a) {
           this->a = a;
           return *this; // ну забыл!
         }


    Насчёт explicit. Конструкторы с одним параметром вообще стоит делать explicit всегда, когда объект семантически отличен от параметра. Например, VeryLongInt(10) или Complex(10) — это та же десятка, и explicit можно опустить. А Vector(10) — динамический массив из 10 элементов ≠ десятке, тут explicit нужен.
    Ответ написан
    1 комментарий
  • Динамическая структура данных. Что это?

    @Mercury13
    Программист на «си с крестами» и не только
    Инструментом для этого, опять-таки, послужит операция new.

    Это и есть критерий ДСД. Всё, где используется динамическая память,— динамическая структура данных.

    Так же яндексом выводится очень много задач/примеров, где дсд применяется к Стеку. В итоге получаем структуры и стек.

    Почему только?
    По организации: одиночный объект, массив, разные виды деревьев, связанный список и комбинации всего этого…
    По семантике: одиночный объект, индексный массив, ассоциативный массив, список, стек, очередь, pimpl (указатель на реализацию), динамическая строка…
    Например, ассоциативный массив (семантика) можно реализовать как дерево поиска (двоичное дерево), а можно как хэш-таблицу (расширяемый динамический массив + куча связанных списков).
    Очередь (семантика) может быть кольцевым списком (динамический массив, возможно, расширяемый), может — расширяемым массивом из динамических массивов (так работает std::deque из C++), может — связанным списком.
    Стандартный подход к строке — динамический массив. Но что делать, если мы, например, клеим и клеим к строке что-то в конец? Или пишем текстовый редактор, где можно вписывать текст в середину? Тоже хитрые структуры.
    Задача Яндекса — проверить испытуемого за несколько минут. Сложную задачу вряд ли за это время разгрызёшь. Потому и любят простые структуры данных.
    Ответ написан
    Комментировать
  • Почему в потоке cout элементы выводятся в другом порядке?

    @Mercury13
    Программист на «си с крестами» и не только
    Дело в том, что между точками следования (это точка с запятой, вызов функции и экономные операции &&, || и ?:) компилятор имеет право переставлять операции как хочет. Вот он и решил вычислять c++ с конца.

    В C++11 нет точек следования, есть «вычисляется прежде», но языка это кардинально не меняет.

    В C++17 это обещают поправить.
    19) In a shift operator expression E1<<E2 and E1>>E2, every value computation and side-effect of E1 is sequenced before every value computation and side effect of E2

    en.cppreference.com/w/cpp/language/eval_order

    ЗЫ. MinGW даже предупреждение выводит, что результат такой строчки явно не определён. И на классе Co тоже (см. флейм с Толстым Лорри).
    Ответ написан
  • Как объединить три одномерных массива в один?

    @Mercury13
    Программист на «си с крестами» и не только
    Я бы свалил их один за другим в один массив или вектор
    www.cplusplus.com/reference/algorithm/copy

    а затем дважды вызвал бы функцию
    www.cplusplus.com/reference/algorithm/inplace_merge

    Если массивы длины 10, 15 и 20, то…
    • Первый раз — std::inplace_merge(v.begin(), v.begin() + 10, v.begin() + 10 + 15);
    • Второй раз — std::inplace_merge(v.begin(), v.begin() + 10 + 15, v.begin() + 10 + 15 + 20);
    Ответ написан
    Комментировать
  • Не проходит компиляцию с любым текстом в TrayIcon->Hint();?

    @Mercury13
    Программист на «си с крестами» и не только
    Здесь используется расширение C++, т.н. свойства. Внешне они выглядят как поля, но при чтении-записи вызывают функции.
    Form1->TrayIcon->Hint = L"Bad";

    И ещё — название Form1 не рекомендуется, назови её как-нибудь fmMain.
    Ответ написан
    Комментировать
  • Как сэмулировать нажатие клавишы Пробел на Arduino?

    @Mercury13
    Программист на «си с крестами» и не только
    Странно: если ардуина — USB-клавиатура, то она передаёт именно нажатие физической клавиши «пробел».
    Впрочем, у вас тут стоит пробел в кавычках " ". Скорее всего, именно в этом ошибка: при плохой проверке типов, присущей Си, в функцию (которая требует char) будет передан адрес строки «пробел».

    Надо Keyboard.press(' '); или Keyboard.write(' ');. В одиночных кавычках. То есть целое число.

    Кроме того, Keyboard.press только нажимает на кнопку, и разбирай, как эту кнопку «отпустить». По крайней мере, моя «лисичка» требует именно ОТПУСКАНИЯ пробела. Как вариант — тот же Keyboard.write, который жмёт и отпускает.
    Ответ написан
    1 комментарий
  • Существует ли реализация 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, вероятно, перенаправление ввода-вывода тоже есть.
    Ответ написан
    Комментировать