-
Постов
1 610 -
Зарегистрирован
-
Посещение
-
Победитель дней
2
Сообщения, опубликованные juvf
-
-
В 26.06.2024 в 12:04, Forger сказал:
это как раз явное, т.к. жестко прописано в стандарте со времен царя гороха )
это называется "неявное". Со времён царя гороха в стандарте с++ говорится, что по умолчанию будет приват. "по умолчанию" - читай "при неявном" ("по умолчанию" - значит когда "нет явного указания"). Более того, в с++14
ЦитатаMembers of a class defined with the `class` key have private access by default; members of a class defined with the `struct` key have public access by default. Access specifiers can be provided explicitly.
-
В 26.06.2024 в 10:25, Arlleex сказал:
Что за final private?
class A final{pivate: A();} - класс А объявлен как final private
class A final{public: A();} - класс А объявлен как final public
имхо
-
В 26.06.2024 в 10:25, Arlleex сказал:
В чем недостатки такой записи?
я не вижу недостатков. я вижу финальный класс, у которого ЕСТЬ приватный конструктор. Т.е. объект этого класса всё таки можно создать (самим классом). Если объявить класс как final privat и удалить конструктор
class MyClass final { public: ... private: MyClass() = delete; };
тут я вижу: 1) от этого класса нельзя наследосаться. 2) нельзя создать объект этого класса. Т.е. не то что пользователь не сможет сделать MyClass obj;, но и не существует ни каких методов в этом классе, чтобы создать объект этого класса, т.е. нет ни каких статический функций (как в синглтоне), аля MyClass *MyClass::create(){return new MyClass); нет.
-
если класс объявлен как 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
-
В 24.06.2024 в 19:32, EdgeAligned сказал:
Даже вот этот, который разбирали прямо сейчас - вынести любые методы можно в .cpp, но если этот же метод сделан шаблонным - уже нельзя.
и в чем тут косяк? это не баг, это фича.
-
В 24.06.2024 в 17:40, razrab83 сказал:
А зачем тут нужна явной специализация? почему не сделать вместо явной специализации просто функцию не заморачиваясь шаблонами?
в отдельном взято случае, возможно просто функция без шаблона лучше/быстрее/понятнее/читаемо.... но, вы написали шаблон
template <typename T> void f(T value) { // Общая реализация для всех типов }
потом его используете (и не толко вы, а все пользователи вашего кода
f<int>(a);
f<uint>(b);
есть некое API, и тут вас торкнуло для uint сделать немного по другому. Можно убрать шаблон для uint и сделать отдельную функци, тогда вы измените API и код, который уже написан и использует f<uint>(b); не будет собираться.
-
В 24.06.2024 в 17:27, Forger сказал:
поскольку в целях безопасности все поля класса должны быть исключительно private (реже protected), то доступ к ним должен быть возможен только через соотв методы этого класса
по мойму тут путаница тёплого с мягким. Задача про которую говорит jcxz - обработать много данных класса за раз (когда нужно однотипно обработать несколько членов класса). При чем тут приват? У вас есть класс с членами приватными (или протект, или паблик - не важно) A1, A2, A3, ... ,An. У этого класса есть паблик метод calcData(). Вызываем этот метод и нужно в нем обработать однотипно свои приватные члены класса.
-
В 23.06.2024 в 20:31, Arlleex сказал:
Я хотел, чтобы в заголовочнике был только "интерфейс" для быстрого охвата глазами. А в реализации уже потроха - туда смотреть не надо.
это не единственная причина убрать шаблон в 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>. Линковщик потом свяжет весь проект.
Итоговый код будет одинаковый в обоих случаях, но время компиляции уменьшится. У каждого метода есть ++ и --.
-
В 24.06.2024 в 13:54, Arlleex сказал:
Т.е. мы говорим компилятору - у нас где-то есть template. А ну-ка создай прототип шаблонной функции с таким-то типом. Так?
да. компилятор создаст вам функцию
void f(int value) { // Общая реализация }
В 02.06.2024 в 19:24, Arlleex сказал:В общем купил себе книжечку, толстееееннную))
а в этой книжке это не изложено? Или там нужно выкуривать эту инфу?
ps так то конечно, лучше сразу получить знания на практике: есть практическая цель - есть вопрос: "а как это решить и в чем различие?". Чем курить книжку долгое время без практики. Все равно половину забудешь. Просто интересно, там это есть или нет?
-
В 24.06.2024 в 13:15, Arlleex сказал:
Имеет ли это какое-то значение? Или это на уровне синтаксиса абсолютно ничего не значит?
имеет. тут стрельнуть себе в ногу можно...
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; }
вобщем как-то так...
-
1
-
-
В 23.06.2024 в 20:31, Arlleex сказал:
Я хотел, чтобы в заголовочнике был только "интерфейс" для быстрого охвата глазами. А в реализации уже потроха - туда смотреть не надо.
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; }
-
2
-
-
В 19.06.2024 в 09:31, EdgeAligned сказал:
А может лучше
а как внутри func() узнать размер arr[]? Можно void func(int *arr, int size), а можно вообще void func(void *arr, int size, MyType type_) - получится пуре СИ ))
-
вроде как в 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; }
-
2
-
-
В 03.06.2024 в 15:55, juvf сказал:
sendData(buf) -> code1()
вот тут мне не понравилось. тут нужно докрутить. возможно нужно ещё одну send перегрузить для массивов.
-
В 03.06.2024 в 13:23, Arlleex сказал:
это фишка компилятора C++, а не библиотек
да самому стало интересно....
// 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. выхлоп
ЦитатаsendCommand(0x12) -> code0()
18
sendCommand(0x12, 0x34) -> code0()
18 52
sendCommand(0x12, 0x34, 0x56) -> code0()
18 52 86
sendData(0x12, 0x34) -> code1()
18 52
sendCommand("hello")) -> code0()
hello
sendData(buf) -> code1()-
1
-
-
В 31.05.2024 в 19:41, Arlleex сказал:
Т.е. можно ли обойтись без обращения к std вовсе?
В 31.05.2024 в 22:15, Arlleex сказал:Было бы здорово, если можно было бы перегрузить реализации send() под 2 варианта: аргумент-массив, и аргумент-список (параметры через запятую).
если без std, то не получится определить переменное кол-во аргументов. для поддержки разного числа аргументов, нужен перегруз функции sendCommand и sendData для одного, двух и трех аргументов. Если нужно больше аргументов, то добавить соответствующие перегрузки.
-
// Основная шаблонная функция 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; }
-
1
-
-
В 24.05.2024 в 11:01, Vlad_G сказал:
На тубчике есть перевод субтитров.
гэ полное. либо текст читай, либо следи за руками. да ещё и перевод корявый. у ЯБ очень даже годный
-
В 26.05.2024 в 14:43, Mty сказал:
А месаджбокс это MessageBuffers видимо? 🙂
нет. месаджбокс - это ящик с сообщениями. реализовывай его как хочешь.
-
В 25.05.2024 в 21:40, Mty сказал:
А можете рассказать что такое месаджбоксы, слоты/сигналы ?
гугл забанил?
В 25.05.2024 в 21:40, Mty сказал:Я что то не встречал подобного во FreeRTOS.
мой ответ касается вообще любой ОС (да и в вопросе про фрииртос ни слова), мой прием также применим и в FreeRTOS. Или вы думаете что в Linux
можно использоватья использую общие данные, а во FreeRTOS нет?Вам ни кто не мешает реализовать свои флаги, эвенты, месаджбоксы, слоты/сигналы в любой ОС.
-
В 19.05.2024 в 18:00, Arlleex сказал:
Ну да, с перегрузкой действительно можно написать примерно то же, что делает борланд)
Ну вот, дожили. Теперь используем всякие финты/костыли/растяжки в пуре с++, чтобы его приблизить к борланду. фэйспалм.
-
У меня такой прием - Не использую общих данных. Не то что, для нескольких потоков, даже для одного потока. Не должны разные таски использовать общие данные. Каждая задача занимается своим делом и своими данными и нефиг ей лезть в чужие данные. Для передачи сообщений в др. таски использую механизмы ОС (флаги, эвенты, месаджбоксы, слоты/сигналы).
-
В 19.04.2024 в 11:01, alm сказал:
Странно. Возможно, от моего провайдера зависит.
VPN на компах включен? Без vpn даже ручками не обновиться, не скачать.
В 19.04.2024 в 11:01, alm сказал:Приведенную выше фразу -
а какое отношение эта фраза имеет к кубу? какой-то пакистанский инженер, что-то там ляпнул...
-
Плавный переход C -> C++ под МК
в Программирование
Опубликовано · Пожаловаться
вангую, что name, это char* Module::name; Иначе, зачем бы приводить const char* к char*? Тут уже проблема.
такая запись во 1-х protected использует, во 2-х в внутри steName всё тоже const char* к char* приводиться. А не лучше бы ли делать const char* Module::name?
Communication() : Module("Communication") {}; - ещё менее перегруженная запись, чем c setName(), не требует protected, не нужно на константную строку ссылаться через неконстантный указатель.