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, пока всё-таки какая-то каша присутствует. Предлагаю лучше разобраться в иерархии и операциях над классами сначала на словах, а потом писать код: в коде сложнее отделять концепции от их реализации. То бишь, предложение моё - детально описать модель на словах. Во-первых, какова задача? Ведь если мы, скажем, хотим вести "бухгалтерию" (учёт личного состава) - это одно, а если нам надо организовать шефство среди студентов - совсем другое. Так что, первый вопрос, ответ на который я выше не нашёл (может, плохо искал, но лучше тогда ещё раз повторить, чтобы всем было очевидно): какую именно задачу нужно решить? Ведь от этого как раз и зависит иерархия сущностей и её конкретная форма. Я выше делал предположения на этот счёт, исходя из своего понимания задачи, но, похоже, я что-то упустил, поэтому лучше это сейчас проговорить, прежде чем мы совсем в дебри уйдём
|
|
|
Записан
|
|
|
|
|