С Новым годом! Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.95/21: Рейтинг темы: голосов - 21, средняя оценка - 4.95
6 / 6 / 1
Регистрация: 13.12.2017
Сообщений: 22

Как правильно использовать существующий объект одного класса в описании другого класса?

01.09.2021, 23:51. Показов 4608. Ответов 24
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Я учусь использовать С++ для программирования микроконтроллеров.
И не могу понять, как выстроить правильно логику программы на С++

Расскажу на конкретном примере.
Допустим, я создал класс для обработки данных поступающих с UART (последовательный порт)
Класс представляет собой кольцевой буфер и несколько методов для работы с ним.
Методы самые простые: сохранить байт в буфер, вытащить байт из буфера, проверить буфер на пустоту, очистить буфер и т.д.

На основе класса я создал объект.
И проблема в том что этот объект должен быть только один, а использоваться он должен во всей программе в том числе и в других классах.

Объектом кольцевого буфера я пользуюсь и в прерывании (что бы положить туда пришедший байт) и в программе (например, для проверки его пустоты), а так же в классе для обработки сообщений и в некоторых других классах.
То есть, существующий объект должен использоваться как самостоятельно, так и в составе других классов.

К примеру, я хочу создать класс обработки принимаемых данных и в этом классе мне нужно как-то организовать взаимодействие с уже существующим объектом кольцевого буфера.
Наследование, дружба не вариант, так как при этом создастся еще один объект кольцевого буфера, а это не допустимо.

Получается, что если я создаю класс, где нужно как то взаимодействовать с буфером, то прямо в описании класса мне нужно использовать уже существующий объект.
Но, на сколько я понимаю, описание класса не должно каким-либо образом ссылаться на уже созданный объект.
Или такое допустимо?
Как быть в таких ситуациях?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
01.09.2021, 23:51
Ответы с готовыми решениями:

Объявление объекта одного класса в описании другого класса
Здравствуйте. Почему при объявлении Student s в классе Teacher не возникает ошибки? Ведь такой объект уже существует. И почему при...

Как отправить объект одного класса в метод другого класса
Начал изучать классы в c++ и в качестве практики решил написать программу которая упрощено симулирует работу завода: #include...

Как связать сигнал одного класса со слотом другого класса, содержащего указатель на объект этого класса?
Подскажите, пожалуйста, как связать сигнал одного класса со слотом другого класса, содержащего указатель на объект этого класса. Буду очень...

24
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
02.09.2021, 00:03
Цитата Сообщение от reti Посмотреть сообщение
объект должен быть только один, а использоваться он должен во всей программе
синглетон
0
6 / 6 / 1
Регистрация: 13.12.2017
Сообщений: 22
02.09.2021, 20:37  [ТС]
Этот синглтон такая мутная хрень с которой и связываться не хочется. Уж лучше я буду использовать статические методы и поля.
Вообще, я крайне был удивлен, что оказывается несмотря на бешеную популярность С++ под микроконтроллеры в виде Ардуино, нет качественного решения таких часто встречающихся ситуаций.
Почти в любом проекте на С++ под микроконтроллеры возникает необходимость создать единственный класс и получать доступ к нему из других классов.

Синглтон, пожалуй, буду в последнюю очередь использовать.
Есть еще вариант передавать в конструктор класса ссылку на существующий класс. Тоже, вроде, неплохое решение. На крайний случай, статические поля с методами.
А на самый крайний вообще отказаться от классов в таких случаях и делать все на обычных функциях как на Си.
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
02.09.2021, 23:19
Цитата Сообщение от reti Посмотреть сообщение
Уж лучше я буду использовать статические методы и поля.
Синглтон - функция, дающая доступ по ссылке к статическому экземпляру класса. Который будет всего один, и который конструироваться тоже будет однократно. Причём конструироваться этот объект будет только при первом вызове функции сиглтона (а не при запуске программы, как те же статические поля класса). Вот разрушаться этот объект будет действительно только по завершении программы и не раньше.

Добавлено через 5 минут
Проблема с синглтоном только в том, что если в программе будешь общаться не с одним, а например с двумя уартами, то придётся перестраивать программу (и вместо синглтона делать "фабрику" - промежуточный класс, который будет управлять созданием и удалением портов).
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12930 / 6798 / 1820
Регистрация: 18.10.2014
Сообщений: 17,205
03.09.2021, 10:52
Цитата Сообщение от reti Посмотреть сообщение
Почти в любом проекте на С++ под микроконтроллеры возникает необходимость создать единственный класс и получать доступ к нему из других классов.
Не класс, а объект класса. Вы же изначально говорили об объекте класса.

Цитата Сообщение от reti Посмотреть сообщение
нет качественного решения таких часто встречающихся ситуаций.
Как это "нет"? Что тут "решать"? Простейшее решение - глобальная переменная. Заведите глобальную переменную и пользуйтесь ей везде.

Синглтон служит для решения сопутствующих вопросов. А если вам это все не нужно, то - глобальная переменная и готово.
0
6 / 6 / 1
Регистрация: 13.12.2017
Сообщений: 22
03.09.2021, 11:55  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Не класс, а объект класса. Вы же изначально говорили об объекте класса.
Да, конечно, объект. Относительно недавно начал изучать С++. Иногда путаюсь в терминологии.

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Как это "нет"? Что тут "решать"? Простейшее решение - глобальная переменная. Заведите глобальную переменную и пользуйтесь ей везде.
Вот только хотелось бы не глобальную переменную а глобальный объект класса, если я правильно выражаюсь. Глобальную переменную я и в Си могу использовать. А хочется объект класса использовать в нужном месте.
Но, проблема то не в этом, а в том, как созданный объект использовать в других классах. А объект класса, конечно, нужно сделать глобальным, если он требует доступа из других файлов.

В общем, для себя я решил, что лучшим вариантом будет создать объект, сделать его глобальным при помощи extern в заголовочном файле.
А что бы объект можно было использовать в других классах, передавать его как ссылку в конструктор того класса, в котором я хочу его использовать. Сейчас тестирую такой способ.
0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
03.09.2021, 12:09
reti, а вы не пробовали почитать про singleton о котором вам говорят?
0
6 / 6 / 1
Регистрация: 13.12.2017
Сообщений: 22
04.09.2021, 11:03  [ТС]
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
reti, а вы не пробовали почитать про singleton о котором вам говорят?
Да, пробовал. И сделал такие выводы:
1. Я плохо понимаю как он работает, значит пока его использовать не буду.
2. Самое главное. Ни разу не видел, что бы кто-то его использовал в программировании Arduino. Значит, есть другие более корректные варианты.
0
фрилансер
 Аватар для Алексей1153
6446 / 5642 / 1128
Регистрация: 11.10.2019
Сообщений: 15,008
04.09.2021, 11:05
reti, выше уже написали про глобальную переменную - это удобнее синглтона
0
6 / 6 / 1
Регистрация: 13.12.2017
Сообщений: 22
04.09.2021, 11:26  [ТС]
Цитата Сообщение от Алексей1153 Посмотреть сообщение
выше уже написали про глобальную переменную - это удобнее синглтона
Видимо, я не совсем понимаю, про что мне говорит уже второй человек) Или меня не совсем понимают)

Под глобальной переменной вы имеете в виду глобальный объект?

Глобальная переменная это переменная которая определена вне всяких функций (или классов, если С++) и к ней можно получить доступ из разных функций программы.
Глобальными переменными в программировании микроконтроллеров я пользуюсь часто, как и многие другие программисты.
Это позволяет очень удобно обмениваться данными между функциями.
Аналогичным образом я хочу использовать созданный объект на С++. Его я тоже хочу сделать глобальным, что бы из любой точки программы обратиться к открытым методам или полям.

А проблема в том, что я хочу создать еще несколько классов в которых я хочу использовать УЖЕ СОЗДАННЫЙ объект. Получается, в описании класса мне нужно ссылаться на конкретное имя созданного объекта, что бы его использовать в этом классе.
0
фрилансер
 Аватар для Алексей1153
6446 / 5642 / 1128
Регистрация: 11.10.2019
Сообщений: 15,008
04.09.2021, 11:34
reti, так в чём именно сложность?

делаешь заголовочник, в нём пишешь класс глобальной переменной и объявляешь саму переменную

CMyGlobalVar.h
C++
1
2
3
4
5
6
7
#pragma once
struct CMyGlobalVar
{
    //.....
};
 
inline CMyGlobalVar global_CMyGlobalVar;
дальше просто включаешь везде, где нужно, этот заголовочник CMyGlobalVar.h

P.S. Если компилятор не поддерживает C++11 и выше, то данный пример можно переписать на более древний стандарт - не так красиво, но работать будет так же

Добавлено через 2 минуты
правда, есть один момент, из-за которого синглтон более приемлим: порядок инициализации глобальных переменных до входа в main может быть произвольным. То есть, данный объект не следует использовать в конструкторах классов других глобальных переменных
0
Just Do It!
 Аватар для XLAT
4201 / 2657 / 654
Регистрация: 23.09.2014
Сообщений: 8,951
Записей в блоге: 3
04.09.2021, 11:54
Цитата Сообщение от reti Посмотреть сообщение
Как правильно использовать существующий объект одного класса в описании другого класса?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
///----------------------------------------------------------------------------|
/// Использовать существующий объект одного класса в описании другого класса.
///----------------------------------------------------------------------------:
#include <iostream>
#define  l(v) std::cout << #v << " = " << v << "\n";
 
///-----------------------------|
/// "Один" класс.               |
///-----------------------------:
struct My1
{
    std::string nameclass{"My1"};
};
 
///-----------------------------|
/// "Другой" класс.             |
///-----------------------------:
struct  My2
{       My2(My1& o) : o1(o) {}
 
    My1& o1; ///<<< В памяти компа ничего не создаётся!  
 
    void info() {l(o1.nameclass)}
};
 
int main()
{
    My1 my1;
    My2 my2(my1);
        my2.info();
}
0
6 / 6 / 1
Регистрация: 13.12.2017
Сообщений: 22
04.09.2021, 12:02  [ТС]
Цитата Сообщение от Алексей1153 Посмотреть сообщение
делаешь заголовочник, в нём пишешь класс глобальной переменной и объявляешь саму переменную
Да, это самая первая мысль, которая мне пришла в голову.
Создаю структуру или класс:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class BufferUart{
    static const uint16_t SIZE_RX_BUFFER = 500; // размер буфера
    uint8_t buffer[SIZE_RX_BUFFER]; // массив буфера
    uint32_t pWrite; // указатель на элемент для записи
    uint32_t pRead; // указатель на элемент для чтения
 
public:
    BufferUart();  // конструктор
    uint8_t pop(); // вытащить байт из буфера
    bool pop(uint8_t &data); // вытащить байт из буфера (в контролем конца буфера)
    void push(uint8_t data); // положить байт в буфер
    bool isEmpty(); // проверка на пустоту
    void clear(); // очистить буфер
};
Далее ТОЛЬКО один раз создаю объект в файле buffer.cpp
C++
1
BufferUart myBufferUart;
В заголовочном файле buffer.h при помощи extern делаю объект видимым везде, где будет включен заголовочный файл buffer.h
C++
1
extern BufferUart myBufferUart;

А ВОТ ДАЛЬШЕ Я НЕ ЗНАЮ КАК ТОЧНО ПОСТУПАТЬ В ТАКИХ СИТУАЦИЯХ:

Хочу сделать класс для обработки поступивших сообщений

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Класс обработка сообщений
class myTreatMessage{
    static const uint8_t SIZE_CMD_MES = 10;     // Максимальный размер команды
    static const uint8_t START_SYMBOL = '(';        // Стартовый символ
    static const uint8_t STOP_SYMBOL = ')';     // Стоповый символ
    ...
 
public:
    void treatMessage(uint8_t &command, uint32_t &value)  // Это функция для обработки сообщений, передает обратно команду (command) и данные (value)
    {
        if(myBufferUart.isEmpty() == true) return; // ВОТ ЗДЕСЬ ПРЯМО В ОПИСАНИИ ДРУГОГО КЛАССА Я ОБРАЩАЮСЬ К УЖЕ СОЗДАННОМУ ГЛОБАЛЬНОМУ ОБЪЕКТУ
        ... // И ДАЛЕЕ ЕЩЕ РАЗ ПРИХОДИТСЯ ОБРАЩАТЬСЯ К УЖЕ СОЗДАННОМУ ОБЪЕКТУ, КОТОРЫЙ ГЛОБАЛЬНО ВИДИМ
    }
 
};
То есть, в методе treatMessage() мне нужно получить доступ у УЖЕ созданному глобальному объекту.

Цитата Сообщение от Алексей1153 Посмотреть сообщение
правда, есть один момент, из-за которого синглтон более приемлим: порядок инициализации глобальных переменных до входа в main может быть произвольным. То есть, данный объект не следует использовать в конструкторах классов других глобальных переменных
ВОТ! И именно поэтому не понятно как быть.
0
фрилансер
 Аватар для Алексей1153
6446 / 5642 / 1128
Регистрация: 11.10.2019
Сообщений: 15,008
04.09.2021, 12:08
Цитата Сообщение от reti Посмотреть сообщение
И именно поэтому не понятно как быть.
вряд ли эти сообщения полетят до входа в main, поэтому просто подключай заголовочник и вперёд.

Либо в конструктор класса class treatMessage передай ссылку на объект BufferUart (и сделай поле-ссылку в классе), тогда переменная может быть и не глобальная, а просто объявленная в main
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
04.09.2021, 12:17
Цитата Сообщение от reti Посмотреть сообщение
А проблема в том, что я хочу создать еще несколько классов в которых я хочу использовать УЖЕ СОЗДАННЫЙ объект. Получается, в описании класса мне нужно ссылаться на конкретное имя созданного объекта, что бы его использовать в этом классе.
Если объект соединения создаётся строго ДО создания остальных объектов, можно по ссылке, как у XLAT. Если может быть создан после - лучше передавать указатель. При необходимости - умный указатель std::shared_ptr (в этом случае объект не будет разрушен, пока все использовавшие его объекты не очистят указатели на него).

Передавать можно вызовом функции этих использующих, а можно и просто заданием поля с указателем в них (но так хуже).
0
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
04.09.2021, 12:21
Цитата Сообщение от reti Посмотреть сообщение
То есть, в методе treatMessage() мне нужно получить доступ у УЖЕ созданному глобальному объекту.
и myTreatMessage - тоже глобальный объект, который ещё и до входа в main может попытаться использовать myBufferUart?
если нет, то в чём проблема?
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
04.09.2021, 12:26
// ВОТ ЗДЕСЬ ПРЯМО В ОПИСАНИИ ДРУГОГО КЛАССА Я ОБРАЩАЮСЬ К УЖЕ СОЗДАННОМУ ГЛОБАЛЬНОМУ ОБЪЕКТУ
Ну ты его и так получил, благо используешь глобальную переменную. Сконструирован этот класс уарта будет в любом случае ДО исполнения функции void treatMessage(), если нет глобальных переменных myTreatMessage или даже если и есть, но данная ф-ция в их конструкторе не вызывается.

Добавлено через 4 минуты
Цитата Сообщение от reti Посмотреть сообщение
Далее ТОЛЬКО один раз создаю объект в файле buffer.cpp
Этого достаточно. Вызов конструктора для него будет осуществлён до вызова main().
0
Just Do It!
 Аватар для XLAT
4201 / 2657 / 654
Регистрация: 23.09.2014
Сообщений: 8,951
Записей в блоге: 3
04.09.2021, 12:31
Цитата Сообщение от reti Посмотреть сообщение
Далее ТОЛЬКО один раз создаю объект в файле buffer.cpp
тут скользко.

общий совет:
ВСЕ глобальные объекты создавайте только в ОДНОМ месте(файле),
ибо порядок инициализации таких объектов в с++ не определен.
1
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
04.09.2021, 12:46
Цитата Сообщение от reti Посмотреть сообщение
if(myBufferUart.isEmpty() == true)
Проверку "масла масляного" делать не обязательно, if и так принимает в качестве аргументов true/false. А ещё он принимает 0 / 1/ 10 / 25 / и прочие целые числа (среди них false это 0, остальные true)
0
6 / 6 / 1
Регистрация: 13.12.2017
Сообщений: 22
04.09.2021, 12:49  [ТС]
Цитата Сообщение от TRam_ Посмотреть сообщение
Ну ты его и так получил, благо используешь глобальную переменную. Сконструирован этот класс уарта будет в любом случае ДО исполнения функции void treatMessage(), если нет глобальных переменных myTreatMessage или даже если и есть, но данная ф-ция в их конструкторе не вызывается.
Тут немного поясню, из-за чего у меня такая проблема появилась.
При программировании встраиваемых систем очень часто нарушаются правила ООП. Без этого программы будут медленными, а памяти и вовсе может не хватить. После того как начал погружаться в философию ООП пришлось в голове перестраивать привычные шаблоны мышления при составлении программ.
И вот такая ситуация, когда по сути описание класса зависит от имени конкретного объекта, вызывает у меня противоречивые чувства. С одной стороны, вроде, так работает, но с другой стороны как то слишком грубо, нарушаются основные концепции ООП. Поэтому подумал, что существует какое-то более элегантное решение.
Ну если так тоже Ok, то приму к сведению.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
04.09.2021, 12:49
Помогаю со студенческими работами здесь

Можно ли объявлять в описании одного класса объекты другого класса
Здравствуйте! Помогите, пожалуйста, разобраться: я описал класс SignalZakon, а теперь хочу создать объекты этого класса (k, T1 и Т2) в...

Ошибка при попытке использовать объект класса в определении другого класса
Муторное название получилось :scratch: Прошу помощи.... есть созданный класс работы со строкой: &quot;MyString.h&quot; class...

Передача конструктору одного класса объект другого класса
Здравствуйте, кодеры. Столкнулся с проблемой. У меня есть 2 класса Camera и Game и соответствующие конструкторы. main.ccp ...

При перегрузке оператора для класса не получается использовать имя переменной такое же, как в описании класса
Описал первый класс,затем - описал второй класс, используя первый,и когда начал перезагружать оператор для второго класса, вылезла...

Как из одного объекта получить объект другого класса?
Форумчане, подскажите. У меня есть два класса: class Category{ private $id = ''; private $parentId = ''; private...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
Расчёт токов в цепи постоянного тока
igorrr37 05.01.2026
/ * Дана цепь постоянного тока с сопротивлениями и напряжениями. Надо найти токи в ветвях. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа и решает её. Последовательность действий:. . .
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
Модель микоризы: классовый агентный подход
anaschu 02.01.2026
Раньше это было два гриба и бактерия. Теперь три гриба, растение. И на уровне агентов добавится между грибами или бактериями взаимодействий. До того я пробовал подход через многомерные массивы,. . .
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru