Указатели на объекты (классы) в Си++ - класс в качестве члена(элемента) класса - работа с указателями. Взаимодействие классов
Primary tabs
Друзья. на практике оказывается важным понимания основных механизмов "налаживания взаимодействия" между классами в Си++
Прежде всего вспомним о нашей задаче, а точнее - о её решении в виде кода на Си++
Я прокомментирую основные моменты "логики" решения ,которые и иллюстрируют возможности взаимодействия классов в Си++:
- материнская плата агрегирует модули оперативной памяти и отвечает за все операции с памятью =
// далее опишем класс материнских плат и создами пару конкретных моделей /* к материнской плате подключаются */ class Mboard // не будем для этого класса описывать никакого конструктора { public: int mmcount; // max modules count =максимальное число модулей //памяти которое поддерживат данная плата int msize;//memory size=объём памяти, оперативы, закреплённой на плате int freemem;// объём свободной оперативной памяти std::string buffer; // содержит символы, записанные в память Mboard() // всё-таки добавил конструктор для инициалл. парамеров { mmcount = 0; msize=0; freemem=0; buffer=""; // изначально - это просто пустая строка) MemoryState(); } std::vector < RAM > ramms; // массив модулей памяти, подключённых к материнской плате void Addm(RAM ramm)//Add module добавление модуля памяти { if (CheckModuleCount()) // если свободное место есть { Mboard::msize=msize+ ramm.size; // прибавляем память к имеющейся freemem = freemem+ ramm.size; // свободной памяти тоже прибавляется ramms.push_back(ramm); // размещаем модуль на системной плате showmess("COMPLETE", "RAM was added !\n"); printf("You've added = %i Mb\n",ramm.size); MemoryState(); } else /*вообще по-идее далее можно было бы сгенеировать исключение но мы просто ограничемся выводом в консоль уведомления о том, что все слоты для оперативной памяти заняты. для этого я просто произведу вызов самодельной функции которая выводит сообщение в консоль - опишем её как статическую в этом же классе- её можно заменить на printf()*/ { showmess("WARNING","No more free slots for RAM ! \n"); MemoryState(); } } void WriteData(std::string str) // пишем в память { /*мы уножаем на 20 - просто чтобы увеличить "вес" каждого символа в оперативной памяти нашего воображаемого компьютера*/ if ((str.size()*20)<=freemem) { Mboard::buffer+=str; freemem=freemem-str.size()*20;//свободная память уменьшается MemoryState(); // выводим инфу о состоянии памяти } else // если строка для записи слишком велика, то = { printf("This string is too big= you need free space = %i Mb ! \n",str.size()*20); MemoryState(); } } void FreeMemory() // выполняем очистку памяти { freemem=freemem+buffer.size()*20;// объём свободной памяти увеличивается buffer=""; //стираем всю информацию MemoryState(); // выводим инфу о состоянии памяти } void MemoryState() // выводит информацию о сотоянии памяти { printf("-------[memory--info]---------------------\n"); printf(">>Symbols in buffer = %s \n",(char *) buffer.c_str()); printf(">>FREE memoty size = %i \n",Mboard::freemem); printf(">>Total memoty size = %i \n",Mboard::msize); printf("------------------------------------------\n"); } protected: // впервые в этом примере мы используем protected! /* это сделано для того, чтобы с одной стороны элементы класса описанные ниже были доступны классам-потомкам (с private такого не получится) а с другой стороны, чтобы внешние классы данные методы вызвать не могли и опратиться к полям - опять же не могли. Так как здесь быдут располагаться методы и данные(хранящиеся в полях) используемые для внутренних вычислений и операции класса - остальным до них дела быть не должно)))*/ int CheckModuleCount() // проверяем - есть ли ещё свободные слоты // для оперативной памяти { int result=0; // if (ramms.size()<=mmcount) result= 1; return result; } };
- Класс под названием "PC" агрегирует в себе классы - материнской платы, клавиатуры, дисплея. =
// ну пора бы уже написать АГРЕГИРУЮЩИЙ КЛАСС - компьютер /*здесь мы не будем демонстрировать наследование - просто напишем один класс, который продемонстрирует.*/ class PC { public: Mboard mboard;// суда заряжаем класс описывающий материнскую плату Display display;// для подключения дисплея Keyboard keyboard; // для клавы CPU cpu;// процессор - правда его комп получает по-умолчанию // - указываем используемый конструктор PC (Mboard mboard):cpu("x86",2) // "x86" и 2 - параметры по умолчанию /* для начала сборки компьютера в его конструктор достаточно просто передать объект "материская плата" причём любой модели ВНИМАНИЕ!= после параметров конструктора идёт список инициаллизации- он необходим для всех членов-классов у которых нет конструктора "без аргументов" (= назв.- "конструтор по-умолчанию") - такой (= "пустой" -не принимающий аргументов) конструктор надо явно прописыть для всех классов, определяющих собственнный конструтор с параметрами. Если же конструтор по умлочанию отсутствует, то следует указать принимаемые аргументы в списке инициаллизации -ч то и сделано выше для cpu = :cpu("x86",2) */ { PC::mboard=mboard; // закрепляем её)) Intel2000 * newcpu =new Intel2000("x86",3,123654); // СОЗДАНИЕ ОБЪЕКТА В(на)) СИ++ )) // далее переопределим те данные, //что были в списке инициализации и снабдим наш класс конкретным процессором PC::cpu = *newcpu;// "прикручиваем" процессор - а вот и переопределение // выше происходит замена одного указателя на другой - так как фактически // объект это указатель из несокльких байт // cpu = newcpu; } PC():cpu("x86",2) // всё-таки определим конструктор по-умолчанию { } void AddDisplay(Display display) { if (display.neededmem<=PC::mboard.freemem) { // display.Connect(PC::mboard);// подключаем дисплей к материнской плате PC::display=display; PC::mboard.freemem=PC::mboard.freemem - display.neededmem;//уменбшаем объём свободной памяти showmess("PC = OK","display was added to your PC =))"); mboard.MemoryState(); } else showmess("PC_ERROR","you haven't enough memory to add this display"); } void AddKeyboard(Keyboard keyboard) { PC::keyboard=keyboard; // keyboard.Connect(mboard); showmess("PC = OK","Keyboard was added to your PC =))"); mboard.MemoryState(); } };
- Класс клавиатуры - должен взаимодействовать с памятью, а потому необходимо "уведомить" класс о существовании материнской платы =
/* опишем класс, позволяющий моделирующий устройство ввода - клавиатуру. этот класс будет просто записывать строки в память*/ class Keyboard { public: Mboard * mboard;// нужно же клаву к чему-то присоединять Keyboard() // оставим в том числе и конструктор по умолчанию { } Keyboard(Mboard* mboard) { Keyboard::mboard=mboard; } void WriteData(std::string str) { (*mboard).WriteData(str); // пишем данные } void Connect(Mboard* mboard) // для подключения к компу после создания самой клавы { Keyboard::mboard=mboard; } };
- внимательно изучите конструктор - вы передаём в него адрес в памяти по которому располагается класс материнской платы
для клавиатуры это делается так (просто беру пример из листинга программы)=//обратите внимание как мы получаем сам адрес элемента в памяти Keyboard* keyboard=new Keyboard(&(yourpc.mboard)); PCshop::yourpc.AddKeyboard(* keyboard); haskeyboard=1;
- дисплей также взаимодействует с компьютером через материнскую плату =
/*далее класс, описывающий дисплей - просто устройство вывода оно будет предъявлять требования к оперативной памяти*/ class Display { public: int neededmem; Mboard* mboard; Display() { neededmem = 20;// пусть этот дисплей требует 20 мегабайт } Display(Mboard *mboard)// конструктор с "быстрым подключением к материнке")) { Display::mboard=mboard; neededmem = 20;// пусть этот дисплей требует 20 мегабайт } void Connect(Mboard* mboard) // для подключения к компу после создания самого дисплея { Display::mboard=mboard; } void ShowData() // для подключения к компу после создания самого дисплея { // опять же обратите внимание на работу с указателями // (*mboard) - это как раз "данные по указателю" /*понимание правил и принципов работы с указателя принципиально важно в Си и Си++*/ char * str = (char *)(*mboard).buffer.c_str() ; printf("\n=======================================\n"); printf("=============DISPLAY==========================\n"); printf("\n %s \n",str); printf("\n=======================================\n"); printf("=======================================\n"); (*mboard).MemoryState(); } };
Основной вывод:
чтобы несколько объектом могли взаимодействовать с одним с учётом изменений ,производимых в этом единственном объекте всеми взаимодействующими (то есть это реально общий объект а не несколько копий - так общей в примере выше является материнская плата и в частности - закреплённая на ней оперативная память) следует создать в объектах, которым необходимо подключиться к общему ,поля содержащие указатели, на этот общий объект
В противном же случае - даже если передать общий объект в конструкторе объектов-клиентов - каждый клиент получит лишь копию!
- Log in to post comments
- 4560 reads