Перейти к содержанию
    

juvf

Свой
  • Постов

    1 610
  • Зарегистрирован

  • Посещение

  • Победитель дней

    2

Весь контент juvf


  1. вангую, что name, это char* Module::name; Иначе, зачем бы приводить const char* к char*? Тут уже проблема. такая запись во 1-х protected использует, во 2-х в внутри steName всё тоже const char* к char* приводиться. А не лучше бы ли делать const char* Module::name? Communication() : Module("Communication") {}; - ещё менее перегруженная запись, чем c setName(), не требует protected, не нужно на константную строку ссылаться через неконстантный указатель.
  2. это называется "неявное". Со времён царя гороха в стандарте с++ говорится, что по умолчанию будет приват. "по умолчанию" - читай "при неявном" ("по умолчанию" - значит когда "нет явного указания"). Более того, в с++14
  3. class A final{pivate: A();} - класс А объявлен как final private class A final{public: A();} - класс А объявлен как final public имхо
  4. я не вижу недостатков. я вижу финальный класс, у которого ЕСТЬ приватный конструктор. Т.е. объект этого класса всё таки можно создать (самим классом). Если объявить класс как final privat и удалить конструктор class MyClass final { public: ... private: MyClass() = delete; }; тут я вижу: 1) от этого класса нельзя наследосаться. 2) нельзя создать объект этого класса. Т.е. не то что пользователь не сможет сделать MyClass obj;, но и не существует ни каких методов в этом классе, чтобы создать объект этого класса, т.е. нет ни каких статический функций (как в синглтоне), аля MyClass *MyClass::create(){return new MyClass); нет.
  5. если класс объявлен как final public и удалить конструктор по умолчанию и явно не определить конструкторы копирования и перемещения, компилятор создаст их автоматически в public. Чтобы гарантированно нельзя было создать объект класса - удалите эти конструкторы. class A final { public: A() = delete; // Удаляем конструктор по умолчанию A(const A&) = delete; A(A&&) = delete; A& operator=(const A&) = delete; A& operator=(A&&) = delete; private: int a; } лучше объявить класс как final private, тогда все неявные конструкторы по умолчанию будут также private
  6. и в чем тут косяк? это не баг, это фича.
  7. в отдельном взято случае, возможно просто функция без шаблона лучше/быстрее/понятнее/читаемо.... но, вы написали шаблон template <typename T> void f(T value) { // Общая реализация для всех типов } потом его используете (и не толко вы, а все пользователи вашего кода f<int>(a); f<uint>(b); есть некое API, и тут вас торкнуло для uint сделать немного по другому. Можно убрать шаблон для uint и сделать отдельную функци, тогда вы измените API и код, который уже написан и использует f<uint>(b); не будет собираться.
  8. по мойму тут путаница тёплого с мягким. Задача про которую говорит jcxz - обработать много данных класса за раз (когда нужно однотипно обработать несколько членов класса). При чем тут приват? У вас есть класс с членами приватными (или протект, или паблик - не важно) A1, A2, A3, ... ,An. У этого класса есть паблик метод calcData(). Вызываем этот метод и нужно в нем обработать однотипно свои приватные члены класса.
  9. это не единственная причина убрать шаблон в cpp и сделать явную инстанцировку. Если реализовать шаблон полностью в *.h. (или в *.h и в *_impl.h), допустим потом если вызвать эту функцию f<int> 10 раз в одном файле, то компилятор встретив первый раз f<int>, сгенерирует код и после ужё встретив в этом файле f<int> компиялтор будет использовать уже сгенерированные код. Но если вы ещё в десяти файлах исходников вызовите f<int>, то компилятор будет гернерить код f<int> для каждого вашего *.cpp, где вы его вызовите. Один раз на каждый *.cpp где хоть раз есть вызов f<int>. Т.е. ваш main.o будет содержать отдельную f<int>, ваш noMain.o будет содержать отдельную f<int>, и все остальные объектники будет каждый содержать свой f<int>. Потом, при линковке, линкер выкинет все дубликаты и будет всего одна f<int> для всех. Если вы вынесете определение шаблона f<int> в *.cpp и сделаете явную инстанцировку, то при компиляции myTemplate.cpp и встетив строчку template void f<int>(int); у вас компиялтор сгенерирует f<int> в отдельный myTemplate.o . При компиляции остальных файлов *.срр генерации f<int> не будет. Получите myTemplate.0 с кодом f<int>. Линковщик потом свяжет весь проект. Итоговый код будет одинаковый в обоих случаях, но время компиляции уменьшится. У каждого метода есть ++ и --.
  10. да. компилятор создаст вам функцию void f(int value) { // Общая реализация } а в этой книжке это не изложено? Или там нужно выкуривать эту инфу? ps так то конечно, лучше сразу получить знания на практике: есть практическая цель - есть вопрос: "а как это решить и в чем различие?". Чем курить книжку долгое время без практики. Все равно половину забудешь. Просто интересно, там это есть или нет?
  11. имеет. тут стрельнуть себе в ногу можно... template<> func<int>(int a) { } //это явная специализация template func<int>(int a); // это явная инстанцировка в чем различие!? Когда нужно сделать отдельную реализацию для белой вороны какого-то типа, то делается явная специализация. поясню на примере Файл myTemplate.cpp #include "myTemplate.h" template <typename T> void f(T value) { // Общая реализация для всех типов } // Реализация явной специализации для типа `unsigned int` template <> void f<unsigned int>(unsigned int value) { printf("Hello unsigned int = %u"); } // Явная инстанцировка для нужных типов template void f<int>(int); template void f<double>(double); Использование #include "myTemplate.h" int main() { int a = -1; double b = 3.14; unsigned int c = 123; f<int>(a); // Использует общую реализацию f<double>(b); //Использует общую реализацию f<unsigned int>(c); //Использует специализированную реализацию, которая выводит "Hello unsigned int = *" return 0; } вобщем как-то так...
  12. I. Стандартный подход отделить мух от котлет через имплементарный заголовок с реализацией в файле myTemplate.h template <typename T> void f(T value); #include "myTemplateImpl.h" // Включаем реализацию здесь Файл myTemplateImpl.h template <typename T> void f(T value) { // Реализация функции } В этом случае мы отделяем объявление и определение шаблонной функции в разные файлы, но включаем файл с реализацией myTemplateImpl в конце файла с объявлением myTemplate.h. II. альтернативный подход Сделать инстанцировку в исходном файле. Файл myTemplate.h template <typename T> void f(T value); Файл myTemplate.cpp #include "myTemplate.h" template <typename T> void f(T value) { // Реализация функции } // Явная инстанцировка для нужных типов template void f<int>(int); template void f<double>(double); Использование #include "myTemplate.h" int main() { float a = 1.0f; double b = 3.14; f<float>(a); //для варианта II ошибка, т.к. нЭт его (нет инстанцировки для float в cpp) f<double>(b); //будет работать для обоих вариантов return 0; }
  13. а как внутри func() узнать размер arr[]? Можно void func(int *arr, int size), а можно вообще void func(void *arr, int size, MyType type_) - получится пуре СИ ))
  14. вроде как в C++ нет прямого способа передать список инициализации {1, 2} в функцию, без std::initializer_list (может ошыбаюсь). Можно использовать перегрузку шаблонной функции или макрос создающий массив template<int N> void f1(int (&arr)[N]) { for (int i = 0; i < N; ++i) { printf("%d ", arr[i]); } std::cout << std::endl; } // Вспомогательная функция template<int... Args> void f2(Args... args) { int arr[] = { args... }; func(arr); } int main() { f2(1, 2); // вызов f2 развернется в вызов f1 с массивом из двух элементов f2(3, 4, 5); // вызов f2 развернется в вызов f1 с массивом из трех элементов //можно без прокладки f2, но кто-то должен создать массив, например макрос #define F3(...) { int temp[] = { __VA_ARGS__ }; f1(temp); } F3(1, 2); F3(3, 4, 5); return 0; }
  15. вот тут мне не понравилось. тут нужно докрутить. возможно нужно ещё одну send перегрузить для массивов.
  16. да самому стало интересно.... // Online IDE - Code Editor, Compiler, Interpreter #include<stdio.h> #include <iostream> template<typename... Args> void send(int firstByte, Args... args) { auto print = [](auto& arg) { std::cout << arg << " "; };//лямда, дла печати каждого аргумента std::cout << (firstByte == 0 ? "code0()" : "code1()") << std::endl; (print(args), ...); std::cout << std::endl; } // Обертка для sendCommand template<typename... Args> void sendCommand(Args... args) { send(0, args...); } // Обертка для sendData template<typename... Args> void sendData(Args... args) { send(1, args...); } int main() { // Примеры использования std::cout << "sendCommand(0x12) -> "; sendCommand(0x12); // вызовется send(0, 0x12) std::cout << "sendCommand(0x12, 0x34) -> "; sendCommand(0x12, 0x34); // вызовется send(0, 0x12, 0x34) std::cout << "sendCommand(0x12, 0x34, 0x56) -> "; sendCommand(0x12, 0x34, 0x56); // вызовется send(0, 0x12, 0x34, 0x56) std::cout << "sendData(0x12, 0x34) -> "; sendData(0x12, 0x34); // вызовется send(1, 0x12, 0x34) // Примеры с массивами и строками std::cout << "sendCommand(\"hello\") -> "; sendCommand("hello"); // вызовется send(0, "hello") unsigned char buf[3] = {0x01, 0x02, 0x03}; std::cout << "sendData(buf) -> "; sendData(buf); // вызовется send(1, buf) return 0; } Проверил тут на с++17. выхлоп
  17. если без std, то не получится определить переменное кол-во аргументов. для поддержки разного числа аргументов, нужен перегруз функции sendCommand и sendData для одного, двух и трех аргументов. Если нужно больше аргументов, то добавить соответствующие перегрузки.
  18. // Основная шаблонная функция send template<typename... Args> void send(int dataCommand, Args&&... args) { if (dataCommand == 0) { std::cout << "sendCommand called with arguments: "; } else { std::cout << "sendData called with arguments: "; } (std::cout << ... << args) << std::endl; } // Обертка для sendCommand template<typename... Args> void sendCommand(Args&&... args) { send(0, std::forward<Args>(args)...); } // Обертка для sendData template<typename... Args> void sendData(Args&&... args) { send(1, std::forward<Args>(args)...); } int main() { // Примеры использования sendCommand(0x12); // вызовется send(0, 0x12) sendCommand(0x12, 0x34); // вызовется send(0, 0x12, 0x34) sendCommand(0x12, 0x34, 0x56); // вызовется send(0, 0x12, 0x34, 0x56) sendData(0x12, 0x34); // вызовется send(1, 0x12, 0x34) // Примеры с массивами и строками sendCommand("hello"); // вызовется send(0, "hello") unsigned char buf[3] = {0x01, 0x02, 0x03}; sendData(buf); // вызовется send(1, buf) return 0; }
  19. гэ полное. либо текст читай, либо следи за руками. да ещё и перевод корявый. у ЯБ очень даже годный
  20. нет. месаджбокс - это ящик с сообщениями. реализовывай его как хочешь.
  21. гугл забанил? мой ответ касается вообще любой ОС (да и в вопросе про фрииртос ни слова), мой прием также применим и в FreeRTOS. Или вы думаете что в Linux можно использовать я использую общие данные, а во FreeRTOS нет? Вам ни кто не мешает реализовать свои флаги, эвенты, месаджбоксы, слоты/сигналы в любой ОС.
  22. Ну вот, дожили. Теперь используем всякие финты/костыли/растяжки в пуре с++, чтобы его приблизить к борланду. фэйспалм.
  23. У меня такой прием - Не использую общих данных. Не то что, для нескольких потоков, даже для одного потока. Не должны разные таски использовать общие данные. Каждая задача занимается своим делом и своими данными и нефиг ей лезть в чужие данные. Для передачи сообщений в др. таски использую механизмы ОС (флаги, эвенты, месаджбоксы, слоты/сигналы).
  24. VPN на компах включен? Без vpn даже ручками не обновиться, не скачать. а какое отношение эта фраза имеет к кубу? какой-то пакистанский инженер, что-то там ляпнул...
  25. да вроде по прежнему работает обновление
×
×
  • Создать...