// pcmodel.cpp : Defines the entry point for the console application.
//
/*
12. Персональный компьютер. Реализуемые объекты:
процессор, память, системная плата, устройства ввода вывода.
Реализовать процедуры ввода/вывода с учетом возможностей оборудования.
Уточнение =
Для каждой задачи необходимо реализовать объектную модель.
В реализации задач должны присутствовать наследование, агрегация и др. взаимодействия классов.
Общение с пользователем осуществляется через консоль путем вызова
наиболее значимых методов классов, позволяющих увидеть основную функциональность задачи.
Для моделирования динамики процессов можно использовать повторяющиеся вызовы пользователем.
*/
#include < Windows.h> // только ради использования функции Sleep() =))
#include < string > // не забываем подключить для работы со строками
#include "stdafx.h"
#include < string.h >
#include < vector > // подключаем чтобы работать с векторами
// далее заголовки самописных функций
void showmess(char*, char*); // для вывода "системных" сообщений
void exitprogram(); // красиво завершат работу программы)
char *simple_read_all( char * , size_t ); // читает строчку произвольного размера
// моделируемого нами компьютера в консоль
void startmodel();/*демонстрацию функционала программы*/
int inputcl(void);
int _tmain(int argc, _TCHAR* argv[])
{
startmodel();
return 0;
}
/*далее массив классов , и их потомков демонстрирующих
базовые примеры работы с классами в си++ - а также , агрегацию, наследование
и другие взаимодействи классов*/
/*для начала - демонстрация наследования в СИ++
ниже - примеры трёх уровней адсракции для описания процессоров
точнее два адстрактных уровня - это процессор вообще и второй слой абстракци -
это процессор семейства интел.
последний же класс в жанном примере это уже конкретный процессор
марки интел*/
class CPU // прародитель для классов, описывающих реализацию процессоров
{
public:
CPU(char* design,int freq)// сигнатура - формат констурктора
{ CPU::design=design;
CPU::freq=freq;} // реализация конструктора прямо внутри тела класса
// об особенностях описания функции внутри класса читайте на этом же ресурсе
char* design; // архитектура (пусть с точки зрения программирования)
int freq; // frequency частота быстродействия в гигагерцах
};
/*далее пример паблик наследования
этот класс обощённо описывает семейство
процессоров Intel - это уже более конктретно*/
class Intel: public CPU // а вот уже некий конкретный проц от интел
{
public:
Intel(char* , int); // конструктор для класса данной можели опишем снаружи
int freq; // frequency частота быстродействия в гигагерцах
protected:
const char * firm ; // защищённое поле фирмы -
//переопределить его извне в потомках будет невозможно
};
// далее указываем базовый конструтор
Intel::Intel(char* design,int freq):CPU(design,freq) // обычно функция класса описывается снаружи - как и в этом случае
{
Intel::design=design;
Intel::freq=freq;
firm="Intel";// вот оно- неизменяемое значение для любого из семейства процессоров Intel
// заметьте - если конфликта имён нет, то можно не указывать пространство имён
/*по умолчанию функциям-членам класса доступны пространства имён класса
а уж конструктор -как ни крути фукция-член класса*/
}
/*далее опять пример паблик наследования
ЭТО КЛАСС УЖЕ КОНКРЕТНЙ МОДЕЛИ ПРОЦЕССОРА*/
class Intel2000 : public Intel // а вот уже некий конкретный проц от интел
{
public:
Intel2000(char*,int,int); // конструктор для класса данной можели опишем снаружи
private:
int id; // пусть серийный номер будет не публичен
// иные объекты описывающие компоненты компьютера
// не смогут узнать его))
};
Intel2000::Intel2000(char* design,int freq,int id):Intel(design,freq) // конструктор для предыдущего класса
// заметьте, что model CPU(model) - как и иные возможные параметры должен
// фигурировать в сигнатуре базовог коструктора-
/* именно на оснавании базового констуктора интерпретатор определит тип параметра -
потому собственно для родительского конструтора и указывается только одно имя - без типа*/
{
design="x86";// пусть эта модель соответсвует архитектуре x86
Intel2000::id=id; // запоминаем серийный номер - его передадим уже когда будем создавать класс
}
//--------дальше один только один вровень абстракции для описания ОПЕРАТИВНОЙ ПАМЯТИ
/* */
class RAM // обобщённый класс для описания модулей оперативной памяти (абстракция)
{
public:
RAM(int size)
{
RAM::size=size;
}
int size;// объём оперативной памяти - значение следует передать в констуртор
};
class RAM1 : public RAM // первый конкретный модуль оперативы
{
public:
RAM1(int size):RAM(size)
{
RAM1::size=200; //независимо от переданного параметра- пусть жто 200 мегабайт для модуля RAM1
}
};
class RAM2 : public RAM // второй конкретный модуль оперативы
{
public:
RAM2(int size):RAM(size)// описываем прямо в теле класса - читайте об особенностях такого описания в "инете"
{
RAM2::size=1000; //независимо от переданного параметра- пусть жто 1000 мегабайт для модуля RAM1
}
};
// далее опишем класс материнских плат и создами пару конкретных моделей
/*
к материнской плате подключаются
*/
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;
}
};
class Mboard1 : public Mboard // это плата с фиксированным числом слотов
{
public:
Mboard1() // так как базовый конструктор описан не был
// то и указывать его не надо
{
mmcount=4; // пусть у неё будет четыре слота
}
};
class Mboard2 : public Mboard // это вторая плата с фиксированным числом слотов
{
public:
Mboard2() // так как базовый конструктор описан не был
// то и указывать его не надо
{
mmcount=3; // а у этой - три слота
}
};
/*далее класс, описывающий дисплей - просто устройство вывода
оно будет предъявлять требования к оперативной памяти*/
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();
}
};
/* опишем класс, позволяющий моделирующий устройство ввода - клавиатуру.
этот класс будет просто записывать строки в память*/
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;
}
};
// ну пора бы уже написать АГРЕГИРУЮЩИЙ КЛАСС - компьютер
/*здесь мы не будем демонстрировать наследование - просто напишем один
класс, который продемонстрирует.*/
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 PCshop
{
public:
PC yourpc;
int hasmboard; //признак того что уже выбрали материнку
int haskeyboard;//признак того что уже выбрали клаву
int hasdisplay;//признак того что уже выбрали клаву
PCshop():yourpc() // конструктор
{
hasmboard=0;
haskeyboard =0;
hasdisplay=0;
}
void ShowMainMenu()
{
showmess("MENU","this's PC shop menu=");
if (!hasmboard) showmess("(1)"," press 1 to choose mather board");
else
{
showmess("(2)"," press 2 to ADD a RAM module to mather board");
showmess("(3)"," press 3 to ADD a display to your PC");
showmess("(4)"," press 4 to ADD a keyboard to your PC");
if (haskeyboard) showmess("(5)"," press 5 to work with your PC");
showmess("(0)"," press 0 to EXIT-> ");
}
char ch = getchar(); // принимаем символ из стандартного потока ввода
inputcl(); // чистив поток ввода от ЭНТЕРА
CallMeinMenuFunc(ch);
}
void CallMeinMenuFunc(char ch)
{
switch (ch) // ВАРИАНТЫ ПАРАМЕТРОВ
{
case '1': // это или иное значение которому может быть равен параметр
{
ShowMboardChoiceMenu();
}
break; // выход из перебора вариантов -иначе будет рассматриваться case 2
case '2': ShowRamChoiceMenu();
break;
case '3':
{
Display* display=new Display(&(yourpc.mboard));
//*display.Connect(yourpc.mboard);// поключаем
PCshop::yourpc.AddDisplay(* display);
hasdisplay=1;
}
break;
case '4':
{
//обратите внимание как мы полeчаем сам адрес элемента в памяти
Keyboard* keyboard=new Keyboard(&(yourpc.mboard));
PCshop::yourpc.AddKeyboard(* keyboard);
haskeyboard=1;
}
break;
case '5':
{
CallPCWorkFunc(); // контекстное меню и операции компьютера
}
break;
case '0': exitprogram();
}
}
void ShowRamChoiceMenu()
{
showmess("Ram Choice menu","this's MboardChoice menu=");
showmess(" (1)","press 1 to choose RAM1");
showmess(" (2)","press 2 to choose RAM2");
char ch = getchar(); // принимаем символ из стандартного потока ввода
inputcl(); // чистив поток ввода от ЭНТЕРА
CallRamChoiceFunc(ch);
}
int CallPCWorkFunc() // обработчик для контекстного меню работы с компьютером
{
for (;;)
{
yourpc.mboard.MemoryState();
showmess("YOUR PC","working menu = ");
showmess(" (1)","press 1 to write data");
showmess(" (2)","press 2 to show data");
showmess(" (3)","press 3 to remove data");
showmess(" (4)","press 4 to come back in PC shop menu");
char ch = getchar(); // принимаем символ из стандартного потока ввода
inputcl(); // чистим поток ввода от ЭНТЕРА
switch (ch) // ВАРИАНТЫ ПАРАМЕТРОВ
{
case '1': //
{
// строчкой ниеж чиатем строку любой длинны из консоли
char* chs = simple_read_all("user text input reading....",5);
std::string str =chs;
yourpc.keyboard.WriteData(str);// вот такой иерархический вызов для записи))
}
break; //
case '2': //
{
if (hasdisplay)
{
yourpc.display.ShowData();
}
else showmess("ERROR"," Go in PC shop and buy display for yout PC ! ))");
}
break;
case '3': //
{
yourpc.mboard.FreeMemory();
}
break;
case '4': //
{
return 1; // выходим в контекст PC-shop
}
}
inputcl();
}
return 1;
}
void CallRamChoiceFunc(char ch) // вызовы для выбора модулей оперативной памяти
{
switch (ch) // ВАРИАНТЫ ПАРАМЕТРОВ
{
case '1': //
{
RAM1 * ram1= new RAM1(20);
PCshop::yourpc.mboard.Addm(*ram1); //
}
break; //
case '2':
{
RAM2 * ram2= new RAM2(20);
PCshop::yourpc.mboard.Addm(*ram2); //
}
break;
}
}
void ShowMboardChoiceMenu() // меню выбора материнской платы
{
showmess("MboardChoice","this's MboardChoice menu=");
showmess("MboardChoice","press 1 to choose mboard1");
showmess("MboardChoice","press 2 to choose mboard2");
char ch = getchar(); // принимаем символ из стандартного потока ввода
inputcl(); // чистив поток ввода от ЭНТЕРА
CallMboardChoiceFunc(ch);
}
void CallMboardChoiceFunc(char ch) // вызовы для выбора материнской платы.
{
switch (ch) // ВАРИАНТЫ ПАРАМЕТРОВ
{
case '1': //
{
Mboard1* mboard1= new Mboard1();
PC* somepc = new PC(*mboard1);
PCshop::yourpc=* somepc; // прикреплям материнску плату
showmess("OK =PC-shop","Mboard1 was added !");
hasmboard=1; // фиксируем факт выбора системной платы
}
break; //
case '2':
{
Mboard2* mboard2= new Mboard2();
PC* somepc = new PC(*mboard2);
PCshop::yourpc=* somepc; /* прикреплям материнску
плату образца2 */
showmess("OK =PC-shop","Mboard2 was added !");
hasmboard=1; // фиксируем факт выбора системной платы
}
break;
}
}
};
//---далее функция которая запускает демонстрацию функционала программы-----------
void startmodel()
{
PCshop* shop = new PCshop();
for (;;)
{
(*shop).ShowMainMenu();
}
}
// -----======================------ДОПОЛНИТЕЛЬНЫЕ ФУНКЦИИ=---========================---------------
// функция выводящая сообщение в консоль
void showmess(char* messtart ,char* text) // start word of message
{
int i=1;
std::string messt = messtart; // конвертировать в string можно неявно
std::string txt = text; // конвертировать в string можно неявно
// далее склеиваем переданный параметы немного их облагородив
txt = "[(!)" + messt +" = " + txt +" ]\n";// а вот и КОНКАТЕНАЦИЯ в СИ++
char* message = (char *) txt.c_str();/*переводим обратно в char *
чтобы использовать далее printf*/
printf(message); // выводим полученную строку в консоль
}
void exitprogram()
{
Sleep(800); ////пауза
printf("\n\n");
printf("Bye! =)"); // прощаемся с пользователем =)
printf("\n\n");
Sleep(1000); // ещё пауза!))
exit(0); // завершаем проргамму
}
#if defined(_WIN32) || defined (_WIN64)
#define IN_WINDOWS 1
#endif
/* эта функция очистит стандартный поток ввода stdin (обычно - консоль)*/
int inputcl(void)
{
if (IN_WINDOWS) fflush(stdin); // если мы в виндоус - просто очищаем поток
else // если же нет -то , так сказать, работаем дальше
{
printf("\n[%s]\n", "If nothing take place - press enter to continue the program execution.");
while (getchar() != '\n'); /*remove \n or other useless data*/
}
return 0;
}
char *simple_read_all( char * prompting_message , size_t user_block_size) /* make sure that the input is clear when you call this function */
{ /**/
char *result;
/*variables and initialization*/
size_t block_size ;
if (user_block_size) block_size = user_block_size; /*если пользователь указал собственный , то выбираем его как рабочий*/
else block_size = 5; /*иначе используем стандартный блок длинной = 5*/
char *block, *temp;
size_t size = block_size;
size_t n = 0; /* здесь будет храниться размерность считанной строки*/
/*printf("\n=[%s]", "[" .prompting_message. " ]" . "\n");*/
if ( prompting_message)
{
printf("%s \n", prompting_message); /* show message wich specify the reason of input reading - for examp "input clearing" */
}
/*function itself */
result = block = (char*)malloc(size); /*выделяем блоку и строке результата память длинной , равной длинне блока разового чтения*/
if (!result) return NULL; /*если при выделении памяти произошла ошибка - отражаем это в переменной результата*/
*result = '\0'; /* используем это присвоивание как признак успешности - см. дальнейшие комментарии после цикла*/
/*этот цик*/
for (;;) /*этот цикл - ключевой в работе данной функции*/
{
if (fgets(block, block_size, stdin) == NULL) /*читаем блок данных стандартой длинн и размещаем данные в переменной "блок"*/
break; /* если при чтении произошла ошибка - выходим из цикла */
n += strlen(block);
if (result[n - 1] == '\n') /* если последний сивол считанной строки - это символ конца строки, то.....*/
break; /*...выходим из цикла */
size += block_size; /* наращиваем размерность строки результата на величину, равную длинне стадартного блока чтения*/
temp = (char*)realloc(result, size); /* переразмещаем данные по адресу возвращаемой строки в новой области большего размера - сохраняем адрес этой области в вспомогаетльную переменную */
if (temp == NULL)
break;
result = temp; /* сохраняем адрес новой области памяти из вспомогательной переменной в оригинальную переменную результата*/
block = result + n; /* перемещаем указатель записи очередного блока данных на первую свободную ячейку памяти в новой области данных*/
}
if (result[0] == '\0') /* если в предыдущем цикле нам не удалось ничего прочитать - освобождаем память,которую "держит" указатель на строку-результат и отражаем неуспешность чтения на возвращаемом значении функции*/
{
free(result); /*...освобождаем память,которую "держит" указатель на строку-результат...... */
result = NULL;/*....и отражаем неуспешность чтения на возвращаемом значении функции*/
}
if ( prompting_message) printf("[%s] \n", "Data was read"); /* show message wich notify about the end of reading input" */
return result;
}
vedro-compota
Mon, 10/22/2012 - 01:50
Permalink
рассуждения и пояснения
рассуждения и пояснения по поводу данного кода находятся здесь.
_____________
матфак вгу и остальная классика =)