| 
			| 
					
						| eugrita 
								Помогающий    Offline | 
								|  | « :  23-06-2011 20:47 »   |  | 
 
 Давно хотел посоветоваться по этому поводу. Ниже рассказано, как я это представляю. Код местами неполный, иногда ошибочный. Поправьте. Мне главное-концепция. C т.зр. UML определены 2 вида ассоциаций - класс агрегат и класс-композиция класс агрегат - С  уничтожением его экземпляра перестают существовать и  объекты его составляющие. (1 Пример не очень удачный т.к. группа не может быть из 1 студента) #include <string>class Tstud
 {
 public:
 int PIN;
 std::string FIO;
 int year;
 Tstud(int ye,std::string fio)
 {}
 };
 class Tgroup //класс агрегат из 1 студента
 {
 public:
 int curs;
 std::string spec;
 Tstud* st;//
 Tgroup(int ye,int tp)
 {
 st=new Tstud(...);
 }
 };
 
Класс композиция. С  уничтожением его экземпляра продолжают существовать и  объекты его составляющие  class Tstud {
 public:
 int PIN;
 std::string FIO;
 int year;
 Tstud(int ye,std::string fio)
 {}
 };
 class Tgroup //класс -композиция из 1 студента
 {
 public:
 int curs;
 std::string spec;
 Tstud st;//один студент, как атрибут класса
 Tgroup(int ye,int tp)
 {
 st=new Tstud(...);
 }
 };
 
Как быть если составляющих однотипных объектов не 1 а несколько? Видимо удобно перейти к динамическим структурам, прежде всего списку или вектору. #include <string>#include <vector>
 using namespace std;
 class Tstud
 {
 public:
 int PIN;
 std::string FIO;
 int year;
 Tstud(int ye,std::string fio)
 {}
 };
 class Tgroup //класс агрегат из нескольких студентов
 {
 public:
 int curs;
 std::string spec;
 vector<Tstud> sv;
 Tgroup(int ye,int tp);
 void add(Tstud st)
 {sv.push_back(st);}
 ~Tgroup()
 { sv.erase();} //не понимаю, при очистке контейнера будут ли уничтожены объекты
 //освободиться ли память ?
 };
 
а для композиции видимо аналогично, только непонятно, что происходит при очистке контейнера и как при этом сохранить объекты, но уничтожить контейнер TGroup?
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dale | 
								|  | « Ответ #1 : 23-06-2011 22:06 »  |  | 
 
 C т.зр. UML определены 2 вида ассоциаций - класс агрегат и класс-композиция UML тут ни при чем, это всего лишь нотация, даже скорее набор нотаций. Агрегаты и композиции имеют смысл и вне контекста UML (и даже рискну предположить, что вне контекста ООП). Кстати, раз уж речь зашла об UML, то и приводили бы примеры на нем, а не на C++. Тогда обсуждение не будет ограничено рамками одного конкретного языка, тем более не самого выразительного в плане объектной ориентированности. Как быть если составляющих однотипных объектов не 1 а несколько? Видимо удобно перейтик динамическим структурам, прежде всего списку или вектору.
 Скорее к коллекции, причем не обязательно динамической. а для композиции видимо аналогично, только непонятно, что происходит при очистке контейнераи как при этом сохранить объекты, но уничтожить контейнер TGroup?
 В случае композиции объект-контейнер должен содержать коллекцию ссылок на объекты-компоненты (или указателей, или что там поддерживает конкретный язык реализации). Тогда при уничтожении композита будут уничтожены лишь ссылки на компоненты, но не сами компоненты. В случае агрегации объект-контейнер в принципе может содержать коллекцию самих объектов-компонентов, если эти объекты не полиморфны (тогда уничтожение контейнера совсем тривиально). Если компоненты полиморфны или на то другие есть причины, контейнер может также содержать коллекцию ссылок на динамически созданные компоненты. В последнем случае при уничтожении агрегата следует позаботиться и об уничтожении его компонентов (например, в деструкторе, если исполняющая система не поддерживает автоматическую сборку мусора). При этом из соображений безопасности следует по возможности избегать передачи компонентов за пределы класса по ссылке. |  
						| 
								|  |  
								|  |  Записан | 
 
 Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
 Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
 
 Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
 |  |  | 
	| 
			| 
					
						| eugrita 
								Помогающий    Offline | 
								|  | « Ответ #2 : 24-06-2011 03:23 »  |  | 
 
 Хорошо. тогда хотелось бы прояснить вопрос с коллекциями на обычном ANSI C++ (не Net где вроде появились доп.средства для коллекций). Я сталкивался с этим лишь на VBВ какую сторону посмотреть?
 Вот выдранное с другой темы определение  коллекции
 "Коллекция - в общем-то, специальный список с конкретизированными под данные нужды методами и свойствами"
 Как создать коллекцию из ссылок на объекты средствами С++?
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dale | 
								|  | « Ответ #3 : 24-06-2011 05:30 »  |  | 
 
 Хорошо. тогда хотелось бы прояснить вопрос с коллекциями на обычном ANSI C++...
 В какую сторону посмотреть?
 Если планируете использовать стандартные средства, тогда и смотреть нужно в сторону стандартной библиотеки, которая гарантированно имеется в любой реализации, - STL. Там имеется довольно приличный набор контейнеров. Вот выдранное с другой темы определение  коллекции"Коллекция - в общем-то, специальный список с конкретизированными под данные нужды методами и свойствами"
 Частный случай. Вообще говоря, коллекция может быть реализована (в том числе и) в виде списка, но есть и другие варианты, которые в определенных условиях удобнее и/или эффективнее. Например, коллекция может быть реализована массивом или хэш-таблицей. Все зависит от требований к конкретной коллекции. Как создать коллекцию из ссылок на объекты средствами С++? Практически все коллекции создаются примерно одинаково - сначала инстанцируется шаблон коллекции, параметризованный нужным типом элементов коллекции, затем экземпляр коллекции заполняется элементами. |  
						| 
								|  |  
								|  |  Записан | 
 
 Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
 Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
 
 Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
 |  |  | 
	| 
			| 
					
						| eugrita 
								Помогающий    Offline | 
								|  | « Ответ #4 : 24-06-2011 07:10 »  |  | 
 
 От модератора: объединил воедино две родственные темы.вот посмотрел разговоры о контейнере из указателей и решил применить для себя. Так верно? #include <string>#include <vector>
 using namespace std;
 class Tstud
 {
 public:
 int PIN;
 std::string FIO;
 int year;
 Tstud(int ye,std::string fio);
 } *pSt;
 Tstud::Tstud(int ye,std::string fio)
 {}
 typedef std::vector<Tstud *> pTstudV;
 class Tgroup //êëàññ àãðåãàò èç íåñêîëüêèõ ñòóäåíòîâ
 {
 public:
 int curs;
 std::string spec;
 //vector <Tstud> sv;
 pTstudV sv;
 Tgroup(int ye,int tp);
 void add(int ye,std::string fio)
 {
 sv.push_back(new Tstud(ye,fio));
 }
 ~Tgroup()
 {
 // sv->erase();//ак очищать вообще вектор?
 }
 };
 
Непонятно вроде как очищать контейнер вектор. Если бы список - есть erase |  
						| 
								|  |  
								| « Последнее редактирование: 27-06-2011 08:41 от Вад » |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dale | 
								|  | « Ответ #5 : 24-06-2011 07:45 »  |  | 
 
 Чем не годится vector::clear? |  
						| 
								|  |  
								|  |  Записан | 
 
 Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
 Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
 
 Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
 |  |  | 
	| 
			| 
					
						| Антон (LogRus) | 
								|  | « Ответ #6 : 24-06-2011 07:48 »  |  | 
 
 eugrita, в твоём случае для каждого из элементов надо вызвать delete, если бы ты хранил не указатели, а сами элементы, то delete не нужен
 |  
						| 
								|  |  
								| « Последнее редактирование: 28-06-2011 05:02 от Антон (LogRus) » |  Записан | 
 
 Странно всё это.... |  |  | 
	| 
			| 
					
						| eugrita 
								Помогающий    Offline | 
								|  | « Ответ #7 : 27-06-2011 06:28 »  |  | 
 
 еще раз привожу отредактированный код. (деструкторов, как видите не писал вообще). Меня кроме озвученных вопросов особо интересует правильно ли я инициализировал статический массив spec? . include <string>#include <stdio>
 #include <vector>
 using namespace std;
 class Tstud
 {
 public:
 int PIN;
 std::string FIO;
 int year;
 Tstud(int ye,std::string fio);
 } *pSt;
 Tstud::Tstud(int ye,std::string fio)
 {year=ye;FIO=fio;}
 typedef std::vector<Tstud *> pTstudV;
 class TgroupA //класс агрегат из нескольких студентов
 {
 public:
 static string spec[3];
 int kol;//кол студентов
 int nSp;//N специальности;
 int curs;//курс
 pTstudV sv;
 TgroupA(int ye,int nsp)
 {nSp=nsp;kol=0;}
 ~TgroupA(){sv.clear();};
 void add(int ye,std::string fio)
 {sv.push_back(new Tstud(ye,fio));kol++; }
 void print()
 {
 for(int i=0;i<kol;i++)
 printf("%s ",sv[i]->FIO);
 }
 };
 string TgroupA::spec[]={string("Защита информации"),string("Вычислительные машины, комплексы"),
 "Менеджмент"};
 
Дело в том, что  данную технологию написания классов я рассматриваю как базовую для написания ряда и других классов. Здесь -именно считаю правильным использовать агрегацию по ссылке- если группу расформируют, студенты останутся. В модели скажем, Авто<-мотор<-карбюратор - аналогично - тачка развалится мотор останется и т.п. А вот в модели дом<-Квартира<-комнаты -чистая композиция - снесли квартиру- снесли и комнаты. Кроме того, типичным приемом проектирования считаю написание статических массивов. Практически в любой модели (хоть комп-системн блок- хард, хоть в автомобильной - классы не бкрутся из воздуха, а из конечного множества стандартных типов-деталей. Описывать которые видимо удобно статическими массивами класса. Согласны?Добавлено через 1 час, 36 минут и 8 секунд: фактически перенес тему дискуссии в родственную этой тему forum.shelek.ru/index.php?topic=17168 . Но могу продолжить и здесь: вот чуть улучшенный код, того ,что писал в начале темы #include <string>#include <stdio>
 #include <vector>
 using namespace std;
 class Tstud
 {
 public:
 int PIN;
 std::string FIO;
 int year;
 Tstud(int ye,std::string fio);
 } *pSt;
 Tstud::Tstud(int ye,std::string fio)
 {year=ye;FIO=fio;}
 typedef std::vector<Tstud *> pTstudV;
 class TgroupA //класс агрегат из нескольких студентов
 {
 public:
 static string spec[3];
 int kol;//кол студентов
 int nSp;//N специальности;
 int curs;//курс
 pTstudV sv;
 TgroupA(int ye,int nsp)
 {nSp=nsp;kol=0;}
 ~TgroupA(){sv.clear();};
 void add(int ye,std::string fio)
 {sv.push_back(new Tstud(ye,fio));kol++; }
 void print()
 {
 for(int i=0;i<kol;i++)
 printf("%s ",sv[i]->FIO);
 }
 };
 string TgroupA::spec[]={string("Защита информации"),string("Вычислительные машины, комплексы"),
 "Менеджмент"};
 
Хочу обратить внимание на статический массив spec. Считаю такой прием типовым при разработках систем классов, так как классы-агрегаты, да и просто собираются не из абстрактных кирпичей, а конечного множества типов-моделей. Типичным приемом при построении агрегатов видимо является и наличие счетчиков количества экземпляров составляющих сложный объект простых объектов. Хочу еще раз поднять вопрос - как хранить полученную систему классов как в файле, так и в БД. (только студиозы при сдаче препам обходятся без этого). Как понимаю как мин есть 2 способа хранения в необъектной СУБД а)класс родитель и наследник - в 1 табл  б)родитель и наследник - в разных табл, причем в табл для наследн - только оригинальные поля объекта-наследника |  
						| 
								|  |  
								| « Последнее редактирование: 27-06-2011 08:04 от eugrita » |  Записан | 
 |  |  | 
	| 
			| 
					
						| Вад | 
								|  | « Ответ #8 : 27-06-2011 08:28 »  |  | 
 
 eugrita, плохой пример, и вот почему. spec является полем класса. Тогда, раз она public - нарушается инкапсуляция, spec доступна напрямую, в том числе и на изменение. Если же сделать её private, то контракт относительно числа поддерживаемых специальностей становится неочевидным (я уж не говорю, что в коде нет никакой проверки на сей счёт). А ведь здесь знание о видах специальностей всё равно просачивается наружу, оно по сути своей не является "внутренним делом" класса.
 
 Если уж и правда число вариантов в модели ограничено, имхо, разумнее сделать глобальное перечисление (enum вне класса), а потом использовать этот тип, а не int, в качестве аргумента конструктора. Тогда внутри класса можешь скрывать всё, что хочешь, вплоть до статического списка констант со строками названий специальностей - это уже не будет настолько грубым решением.
 
 Добавлено через 4 минуты и 13 секунд:
 Студенты-то останутся, но специальность - это разве атрибут студента? А не его учебной группы или, шире, "специальности"? У тебя странная иерархия. К твоей модели (студентов могут переводить из группы в группу) напрашивается иерархия специальность->курс->группа->студент, а не наоборот.
 |  
						| 
								|  |  
								| « Последнее редактирование: 27-06-2011 08:33 от Вад » |  Записан | 
 |  |  | 
	| 
			| 
					
						| eugrita 
								Помогающий    Offline | 
								|  | « Ответ #9 : 27-06-2011 08:34 »  |  | 
 
 согласен. Это упустил.Поправлю |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Вад | 
								|  | « Ответ #10 : 27-06-2011 08:42 »  |  | 
 
 Объединил две темы в одну - другой теме данная ветка менее соответствует, всё-таки. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| eugrita 
								Помогающий    Offline | 
								|  | « Ответ #11 : 27-06-2011 08:47 »  |  | 
 
 хорошо
 Добавлено через 2 минуты и 58 секунд:
 согласен с замечанием относительно private и public  для spec. (да только у меня spec - атрибут не Tstud, а TGroup - откуда считаете что атрибут студента?). C enum может действительно правильнее,
 |  
						| 
								|  |  
								| « Последнее редактирование: 27-06-2011 08:50 от eugrita » |  Записан | 
 |  |  | 
	| 
			| 
					
						| Вад | 
								|  | « Ответ #12 : 27-06-2011 08:51 »  |  | 
 
 Что касается иерархии, то я бы рассуждал так: коль скоро в нашей модели группу могут расформировывать, а студентов - переводить в другие группы (оставлять на второй год, менять специальность), логично воспроизвести, на каком уровне принимается решение всякий раз:  - если это перевод из группы в группу в рамках курса и специальности, то затрагиваются только две заинтересованные группы (из одной студент удаляется, в другую - добавляется) - то же самое, если оставили "на второй год" (отчислили с восстановлением, дали академ. отпуск, и т.п.) - нужно только найти две группы и обеспечить проверку, чтобы студента не перевели на два курса старше (хотя при экстернате возможно и такое) - если нужно упразднить всю группу, не видно никаких проблем: всё равно кто-то "сверху" должен управлять её разделением. При этом, только в случае смены специальности студентом мы поднимаемся именно на уровень специальности. Таким образом, мне более естественной представляется модель, в которой специальность состоит из групп разных курсов (при этом не надо дублировать информацию о специальности каждого студента - он принадлежит той же специальности, что и вся его группа, а принадлежность группе может выглядеть по-разному: в объектной модели - как агрегация в группу, если нет других резонов; в БД же - как атрибут студента). Группы, в свою очередь, агрегируют списки студентов. В этой схеме ничто никуда не девается само и самовольно: раз студент не волен сам менять группу (в смысле, встал и перешёл), то за перевод его отвечает не он сам, а кто-то, управляющий группами (чиновники ВУЗа).Добавлено через 2 минуты и 10 секунд: согласен с замечанием относительно private и public  для spec. (да только у меня spec - атрибут не Tstud, а TGroup - откуда считаете что атрибут студента?). C enum может действительно правильнее, 
 Да, прошу прощения, загляделся, немного домыслил    А зачем студенту год - это год рождения? И PIN - что это где оно участвует? |  
						| 
								|  |  
								| « Последнее редактирование: 27-06-2011 08:53 от Вад » |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #13 : 27-06-2011 09:13 »  |  | 
 
 По поводу хранения - см. в сторону сериализации и ООБД. |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Dale | 
								|  | « Ответ #14 : 27-06-2011 09:16 »  |  | 
 
 Хочу обратить внимание на статический массив spec. Считаю такой прием типовым при разработках систем классов Обоснуйте, пожалуйста. Типичным приемом при построении агрегатов видимо является и наличие счетчиков количества экземпляров составляющих сложный объект простых объектов. Этот тезис тоже кажется мне сомнительным. |  
						| 
								|  |  
								|  |  Записан | 
 
 Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
 Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
 
 Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
 |  |  | 
	| 
			| 
					
						| eugrita 
								Помогающий    Offline | 
								|  | « Ответ #15 : 27-06-2011 17:19 »  |  | 
 
 Ваду: в ваших замечаниях много рационального. Вот поправил систему классов (еще не окончательно). Заменил  класс Tstud структурой. Скрыл излишние члены данных.  Конечно ни к месту инициализированный статический массив spec , его заменил на  vector<string> spec и инициализировал параметрами конструктора Tpotok Пока вот так: #include <string>#include <stdio>
 #include <vector>
 using namespace std;
 
 struct Tstud {//студент
 string PIN; //идентификац номер студ
 string FIO;//фам имя отч
 int status;//0- ок, 1- отчислен, 2-перевод в др группу
 };
 
 typedef std::vector<Tstud *> pTstudV;
 
 class TgroupA //класс "Учебн.группа" -агрегат из нескольких студентов
 {
 public:
 int year;//год зачисления
 TgroupA(int crs) //конструктор группы с параметром год создания
 {sv.clear();curs=crs;}
 ~TgroupA(){sv.clear();};
 
 void add(int ye,std::string fio)
 {
 Tstud *p = new Tstud;
 p->FIO=fio; p->PIN=this->GetKol();
 sv.push_back(p);
 }
 void print()
 {
 printf (" god=%i\n",year);
 for (int i=0;i<this->GetKol();i++)
 printf("%s ",sv[i]->FIO);
 }
 private:
 pTstudV sv;//контейнер ссылок на экз Tstud
 int curs;//курс
 int GetKol();//кол студентов
 };
 int TgroupA::GetKol()
 {return this->sv.size();}
 
 typedef vector<TgroupA *> pTgr;
 class Tpotok //класс -поток из групп 1 специальности
 {
 private:
 
 int nSp;//N специальности
 pTgr sp;//контейнер из 5 групп
 vector <string> spec;
 public:
 Tpotok(int ns, int n,string *ps) {//конструктор
 for (int i=0;i<n;i++)
 spec.push_back(ps[i]);
 if (ns <0 || ns >2) printf("error ");
 nSp=ns;
 for (int i=0;i<5;i++)  {
 TgroupA * g=new TgroupA(i+1);sp.push_back(g);
 }
 }//конструктор
 void setYear(int ye) { //установка года для всех групп потока
 if (ye>1990 && ye < 2011)
 for (int i=0;i<5;i++) sp[i]->year=ye;
 }
 void addStud(int ye,string fio,int ngr) {
 sp[ngr]->add(ye,fio);
 }
 void print (int crs)
 { //печать группы курса crs
 printf("\n curs=%i  ",crs);
 if (crs>0 && crs<5) sp[crs]->print();
 }
 string getSpec() //возвращает назв специальности потока
 {return spec[nSp];}
 void perevod () {//перевод студентов групп на следующий курс или выпуск
 
 }
 };
 ...
 #include "groupagr.h"
 #include <string>
 int main()
 {
 string s[]={string("Защита информации"),string("Вычислительные машины,комплексы"),"Менеджмент"};
 Tpotok * pt=new Tpotok(1,3,s);
 pt->addStud(1995,"Ivanov I.E.",1);pt->addStud(1994,"Petrov A.P.",1);
 pt->addStud(1993,"Malskaya M.O.",1);pt->addStud(1995,"Shoixet K.E.",1);
 pt->addStud(1994,"Tolstunov D.F.",1);
 pt->addStud(1993,"Akivis T.",2);pt->addStud(1994,"Arutunan E.",2);
 pt->setYear(2005);
 pt->print(1);   pt->print(2);
 system("pause");
 return 0;
 }
 
 
 |  
						| 
								|  |  
								| « Последнее редактирование: 27-06-2011 20:47 от eugrita » |  Записан | 
 |  |  | 
	| 
			| 
					
						| Вад | 
								|  | « Ответ #16 : 27-06-2011 21:11 »  |  | 
 
 eugrita, пока всё-таки какая-то каша присутствует. Предлагаю лучше разобраться в иерархии и операциях над классами сначала на словах, а потом писать код: в коде сложнее отделять концепции от их реализации. То бишь, предложение моё - детально описать модель на словах. Во-первых, какова задача? Ведь если мы, скажем, хотим вести "бухгалтерию" (учёт личного состава) - это одно, а если нам надо организовать шефство среди студентов - совсем другое. Так что, первый вопрос, ответ на который я выше не нашёл (может, плохо искал, но лучше тогда ещё раз повторить, чтобы всем было очевидно): какую именно задачу нужно решить? Ведь от этого как раз и зависит иерархия сущностей и её конкретная форма. Я выше делал предположения на этот счёт, исходя из своего понимания задачи, но, похоже, я что-то упустил, поэтому лучше это сейчас проговорить, прежде чем мы совсем в дебри уйдём   |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	|  |