Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: 1 2 [Все]   Вниз
  Печать  
Автор Тема: Базовые и порожденные классы  (Прочитано 34453 раз)
0 Пользователей и 2 Гостей смотрят эту тему.
ezus
Опытный

il
Offline Offline

« : 25-08-2010 10:39 » 

Опять запутался в языках и что-то не понимаю в С++.

Есть 2 класса Pattern и Shape, которые наследуют от общего класса Keta.
Код:
class Keta  
{
public:
Keta();
virtual ~Keta();
bool _isPattern;
virtual void locate()=0;
};
class Pattern : public virtual Keta
{
public:
Pattern();
virtual ~Pattern();
void fp();
void locate();
};
class Shape : public virtual Keta
{
public:
Shape();
virtual ~Shape();
void fs();
void locate();
};

Есть смешанный массив указателей на оба класса
Код:
CPtrArray arr;  arr.SetSize(0,1);
Pattern* ptr = new Pattern;
arr.Add(ptr);

Shape* shp = new Shape;
arr.Add(shp);
Читая этот массив, я естесственно не знаю тип текущего объекта, поэтому

Keta* keta = (Keta*)arr.GetAt(i);

1. Могу ли я, зная исходный тип объекта, получить указатель соответствующего типа?
Например:
Код:
if( keta->_isPattern )
Pattern* ptr = (Pattern*)keta:
или
Pattern* ptr = keta:

2. В чем моя ошибка в определении виртуальной функции    
virtual void locate()=0; ?

Программа падает при
keta.locate();

Спасибо.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #1 : 25-08-2010 11:00 » 

1) можно, но не нужно
2)а код функций void locate() покажи )
« Последнее редактирование: 25-08-2010 11:01 от Алексей1153++ » Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #2 : 25-08-2010 11:20 » 

можно и иногда нужно
можно доже если ты не знаешь тип элемента Улыбаюсь при использовании RTTI и dynamic_cast
http://alenacpp.blogspot.com/2005/08/c.html
Записан

Странно всё это....
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #3 : 25-08-2010 11:30 » 

1) можно, но как сказал пушистый не нужно, но если очень хочется, то так
Keta* object = (Keta*)arr.GetAt(i);
Pattern * pattern = 0;
Shape * shape = 0;

pattern = dynamic_cast<Pattern *>(object);
if (!pattern)
{
  shape = dynamic_cast<Shape *>(object);
  if (!shape)
    ;// ЖОПА
}

2) падает в рантайме или просто ошибка при компиляции или линковке, если в рантайме, то код ошибки и реализацию метода в потомке показывай
Записан

С уважением Lapulya
ezus
Опытный

il
Offline Offline

« Ответ #4 : 25-08-2010 11:37 » 

1) можно, но не нужно
Нужно.
В случае Pattern необходимо выполнить функцию fp();
а  случае Shape необходимо выполнить функцию fs();
Заранее хочу отметить, что имена этих функций разные, потому что они просто разные.
Цитата
2)а код функций void locate() покажи )
void Pattern::locate() { puts("Pattern::locate\n"); }
void Shape::locate() { puts("Shape::locate\n");  }
Записан
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #5 : 25-08-2010 11:41 » 

1) тебе виднее на сколько они разные, но в любом лучае ответ дан. Кстати, операция dynamic_cast не быстрая, так что думай!
2) еще раз говорю
Цитата
падает в рантайме или просто ошибка при компиляции или линковке, если в рантайме, то код ошибки
Записан

С уважением Lapulya
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #6 : 25-08-2010 11:58 » 

Нужно.
В случае Pattern необходимо выполнить функцию fp();
а  случае Shape необходимо выполнить функцию fs();
Заранее хочу отметить, что имена этих функций разные, потому что они просто разные.

А полиморифизм на что? Объяви в Keta, одну виртуальную ф-ю f() и переопредели её в Pattern с телом fp и с телом fs в Shape. В чём проблема?
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
ezus
Опытный

il
Offline Offline

« Ответ #7 : 25-08-2010 12:02 » 

А что такое "object " в
Keta* object = (Keta*)arr.GetAt(i); ?

Это какой-то третий объект, отличный от того, что был помешен в arr?

Просто раньше я работал в Java, а там таких заморочек не возникало, поэтому я никак не могу проникнуться кишками С++.
Записан
ezus
Опытный

il
Offline Offline

« Ответ #8 : 25-08-2010 12:06 » 

Нужно.
В случае Pattern необходимо выполнить функцию fp();
а  случае Shape необходимо выполнить функцию fs();
Заранее хочу отметить, что имена этих функций разные, потому что они просто разные.

А полиморифизм на что? Объяви в Keta, одну виртуальную ф-ю f() и переопредели её в Pattern с телом fp и с телом fs в Shape. В чём проблема?
Я же отметил, что это ПРИНЦИПИАЛЬНО разные функции, и объединять их под общим именем не вижу никакого смысла, кроме чисто программистских заморочек, которых всегда старался избегать.
Записан
ezus
Опытный

il
Offline Offline

« Ответ #9 : 25-08-2010 12:07 » 

За
 Pattern* ptr = dynamic_cast<Pattern *>(keta);
СПАСИБО.

Но я получаю
warning C4541: 'dynamic_cast' used on polymorphic type 'class Keta' with /GR-; unpredictable behavior may result

Как можно избежать данного предупреждения?
Записан
ezus
Опытный

il
Offline Offline

« Ответ #10 : 25-08-2010 12:11 » 

На
Keta* keta = (Keta*)arr.GetAt(i);
keta->locale();

получаю
"Unhandled exception in tst.exe: 0x0000005: Access Violation"
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #11 : 25-08-2010 12:22 » 

Я же отметил, что это ПРИНЦИПИАЛЬНО разные функции, и объединять их под общим именем не вижу никакого смысла, кроме чисто программистских заморочек, которых всегда старался избегать.

Если имя ф-ции как заноза в глазу, назови её CallSpecialFunction() и тогда

Код:
void Pattern::CallSpecialFunction()
{
      fp();
}

...

void Shape::CallSpecialFunction()
{
      fs();
}


Ну, если ООП чисто программисткая заморочка, то зачем его использовать? Есть прекрасное функциональное программирование. А в данном случае, как раз притягивание типов за уши для этой цели, есть в высшей степени нелепость. Ибо переписанные функции классов-потомков просто обязаны быть ПРИНЦИПИАЛЬНО разными, иначе нафига они вобще нужны?
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #12 : 25-08-2010 12:43 » 

Джон, ezus правильно говорит, нельзя так делать, если следовать твоему предложению, то:
1. Это уже не наследование по логике (наследуемые классы наследуют поведение предка, а тут сразу нарушение этого правила)
2. Так можно решить только частную задачу, ну например, у меня таких массивов 100 штук и в каждом из них должна быть разная обработка объектов в зависимости от типа, чтож мне миллион функций в эти классы впихать, чтоб при любой обработке вызвать одну, но виртуальную?

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

Цитата
Код:
Keta* keta = (Keta*)arr.GetAt(i);
keta->locale();

получаю
"Unhandled exception in tst.exe: 0x0000005: Access Violation"

Чему равно:
1. keta при вызове?
2. верно ли, что объект вынутый из массива действительно типа Keta (т.е. dynamic_cast<Keta*>(arr.GetAt(i)) вернет не 0)?
« Последнее редактирование: 25-08-2010 12:45 от lapulya » Записан

С уважением Lapulya
ezus
Опытный

il
Offline Offline

« Ответ #13 : 25-08-2010 12:48 » 

Я чувствую - начали переходить на личности?
Очень бы не хотелось.
Попробую ответить корректно.

Если имя ф-ции как заноза в глазу, назови её CallSpecialFunction() и тогда
Фунция "CallSpecialFunction()" будет такой же "занозой в глазу" как и любая другая.
Функция должна рождаться из задачи, а если это не так, то она именно "программисткая заморочка", и их надо минимизировать, оставляя только самые необходимые, без которых на данной платформе задача просто не решается.
Цитата
Ну, если ООП чисто программисткая заморочка, то зачем его использовать?
Мне кажется вы путаете ООП с С++. Это далеко не одно и тоже.

Цитата
Есть прекрасное функциональное программирование. А в данном случае, как раз притягивание типов за уши для этой цели, есть в высшей степени нелепость.
Причем здесь "прекрасное функциональное программирование"?
И в чем заключается "притягивание типов за уши для этой цели"?
Какой цели?
И в чем "высшая степень нелепости"?

Цитата
Ибо переписанные функции классов-потомков просто обязаны быть ПРИНЦИПИАЛЬНО разными, иначе нафига они вобще нужны?
Интересный взгляд на ООП.
Т.е. полиморфизм подразумевает, что в одном случае виртуальная фунция "расчет сметы" будет выполнять чистку базы данных, а в другом печать расписания паровозов?

Записан
ezus
Опытный

il
Offline Offline

« Ответ #14 : 25-08-2010 12:51 » 

Чему равно:
1. keta при вызове?
2. верно ли, что объект вынутый из массива действительно типа Keta (т.е. dynamic_cast<Keta*>(arr.GetAt(i)) вернет не 0)?
Код:
	Pattern* ptr = new Pattern;
arr.Add(ptr);
Keta* keta = (Keta*)arr.GetAt(0);
keta->locate();
Записан
ezus
Опытный

il
Offline Offline

« Ответ #15 : 25-08-2010 12:55 » 

Похоже я насщупал ошибку, хотя все равно не понимаю.
Вместо
arr.Add(ptr);
надо
arr.Add((Keta*)ptr);

И тогда похоже работает.
Жалко, что проверить смогу только завтра.
Записан
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #16 : 25-08-2010 13:00 » 

ну наверное не так
Цитата
Код:
Pattern* ptr = new Pattern;
,а так
Код:
Pattern* ptr = new Pattern();

И чему всеже равно keta?

Цитата
Код:
Pattern* ptr = new Pattern;
arr.Add(ptr);
Keta* keta = (Keta*)arr.GetAt(0);
keta->locate();
Был ли arr пуст?
Записан

С уважением Lapulya
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #17 : 25-08-2010 13:01 » 

Цитата
Похоже я насщупал ошибку, хотя все равно не понимаю.
Вместо
arr.Add(ptr);
надо
arr.Add((Keta*)ptr);

Не, тут по идее никакой разницы (т.е. это абсолютно одно и тоже).
Записан

С уважением Lapulya
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #18 : 25-08-2010 13:06 » 

ezus,  это

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

я не Джону, а тебе писал Улыбаюсь
Записан

С уважением Lapulya
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #19 : 25-08-2010 13:14 » 

Просто раньше я работал в Java, а там таких заморочек не возникало, поэтому я никак не могу проникнуться кишками С++.
Указатель в С++ ~= ссылке (ссылочному типу) в Java, с поправкой на то, что управления временем жизни и сборки мусора нет, а прямая адресация памяти открывает бескрайние просторы для всякого. Соответственно, как указатели ни приводи, объект фактически будет существовать один - тот, который создан, в данном случае, конструкцией new Type; (конструктором по умолчанию на куче). Всё остальное ссылается именно на эту область памяти. И надо не забыть его удалить, т.к., см. выше, сборки мусора нет.
Записан
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #20 : 25-08-2010 13:40 » 

Цитата
Похоже я насщупал ошибку, хотя все равно не понимаю.
Вместо
arr.Add(ptr);
надо
arr.Add((Keta*)ptr);

Не, тут по идее никакой разницы (т.е. это абсолютно одно и тоже).

Разница есть, она в том, что в первом случае происходит преобразование Pattern* -> void*, а во втором - Pattern*->Keta*->void*. Преобразование Pattern*->void*->Keta* будет некорректным (рекомендую попробовать), потому что таблицу виртуальных функций класса Pattern поломает начисто - он ведь виртуально отнаследован.
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #21 : 25-08-2010 14:18 » 

Джон, ezus правильно говорит, нельзя так делать, если следовать твоему предложению, то:
1. Это уже не наследование по логике (наследуемые классы наследуют поведение предка, а тут сразу нарушение этого правила)

Из чего следует это утверждение? А если это просто интерфейсная ф-я? О каком поведении предка и наследовании этого поведения можно вобще говорить, если это абстрактный (мне больше нравится слово "интерфейсный" или просто "интерфейс") класс? Или ты можешь описать поведение объекта Keta? Ага ООП как раз и предоставляет возможность разрешить проблему "персонализации" объекта при вызове специальной ф-ции. Есть указатель только на родительский класс. Всё. Больше ничего. Какая разница, что там воплощено. Это уже головная боль потомка.

2. Так можно решить только частную задачу, ну например, у меня таких массивов 100 штук и в каждом из них должна быть разная обработка объектов в зависимости от типа, чтож мне миллион функций в эти классы впихать, чтоб при любой обработке вызвать одну, но виртуальную?

Ничего не понял. Если у тебя таких массивов миллион, то ф-я всё-равно будет одна.

Я чувствую - начали переходить на личности?

Ни в коем случае. Ничего личного. Я просто в своё время сам проходил через это - преобразование родительского типа к конкретному. Любое такое преобразование - проявление анти ООП настроений. Указывет исключительно на слабо продуманную архитектуру. Прочитай, первые три ответа на свой первый вопрос, заметь, других участников. Поэтому на личности перехода нет и не будет.

Цитата
Фунция "CallSpecialFunction()" будет такой же "занозой в глазу" как и любая другая.
Функция должна рождаться из задачи, а если это не так, то она именно "программисткая заморочка", и их надо минимизировать, оставляя только самые необходимые, без которых на данной платформе задача просто не решается.

Согласен и 100% поддерживаю, но только когда речь идёт о реализации какой-то конкретной, чётко сформулированной задачи. Но когда одна ф-я выполняет работу целой библиотеки, это тоже не есть гут. Согласись? В этом случае такого монстра необходимо разбить на более мелкие задачи, что автоматически повлечёт за собой производство кучи маленьких вспомогательных ф-ций. В твоём же случае, речь идёт о ф-ции, которая управляет другими ф-ми, она их вызывает. Что же в этом плохого? Немного другая степень абстракции.

Цитата
Мне кажется вы путаете ООП с С++. Это далеко не одно и тоже.
В чём? Я как раз очень хорошо знаю, что С++ это далеко не идеальный язык для ООП. Поэтому в последнее время всё чаще и чаще повторяю одну очень хорошую мысль Трея Нэша, даже вынес её в подпись:
"Just because the language allows you to do something does not mean that it’s the correct thing to do."

Как раз такой случай, то что С++ позволяет приводить типы, ещё не значит, что надо так всегда делать.

Цитата
Причем здесь "прекрасное функциональное программирование"?
Ну как при чём, именно  оно позволяет создать минимум функций для реализации конкретной задачи. Без всяких заморочек. Или не так?

Цитата
И в чем заключается "притягивание типов за уши для этой цели"?

Вот в этом:

if( keta->_isPattern ) Pattern* ptr = (Pattern*)keta

Твой пример только для наглядности (никаких личностей). Также это относится и к безопасным кастингам а ля dynamic_cast.

Цитата
Какой цели?
Вызвать специальную, существующую только в этом классе (кстати потомке) ф-ю.

Цитата
И в чем "высшая степень нелепости"?

Ну сравни сам это:

Код:
Keta* object = (Keta*)arr.GetAt(i);
Pattern * pattern = 0;
Shape * shape = 0;

pattern = dynamic_cast<Pattern *>(object);
if (!pattern)
{
  shape = dynamic_cast<Shape *>(object);
  if (shape)
  {
      pattern->fs();
  }
   else
   {
        // ЖОПА
   }
}
else
{
     pattern->fp();
}

и это:

Код:
Keta* object = (Keta*)arr.GetAt(i);
object->f();


Цитата
Интересный взгляд на ООП. Т.е. полиморфизм подразумевает, что в одном случае виртуальная фунция "расчет сметы" будет выполнять чистку базы данных, а в другом печать расписания паровозов?

КОНЕЧНО! Ибо глупость человеческая, в отличие от вселенной, безгранична. Если, ТАК спроектировать, то будет не только расписание паровозов. Ага На самом деле всё гораздо проще. Классический пример с геометрическими фигурами. Чертить окружность есть совсем не то, что строить треугольник. Но оба они представляют собой некий процесс. Поэтому родительский класс Фигура получает ф-ю Нарисовать(). А уже Треугольники, Квадраты и прочие дети, сами выполняют то, что им нужно.
Если два класса имеют общего предка, то значит их что-то объединяет. Иначе предок не нужен вобще. Поэтому и ф-ции предка, имеют как правило обобщённый смысл. Рисовать, Удалить, Переместить. А "расписание паровозов" и "расчет сметы" всё-таки узкоспециаллизированные задачи. Поэтому они не могут напрямую выполняться какими-то прямыми потомками одного родителя. Как я уже сказал, всё зависит от архитектуры проекта.
Если это имеет смысл, то какой-нить класс-потомок в десятом колене, действительно будет вычислять смету, а его десятиюродный братец в это же вермя расписывать паровозы, и оба, как результат некоего общего начального действия.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #22 : 25-08-2010 15:33 » 

Цитата
Из чего следует это утверждение? А если это просто интерфейсная ф-я? О каком поведении предка и наследовании этого поведения можно вобще говорить, если это абстрактный (мне больше нравится слово "интерфейсный" или просто "интерфейс") класс? Или ты можешь описать поведение объекта Keta?  ООП как раз и предоставляет возможность разрешить проблему "персонализации" объекта при вызове специальной ф-ции. Есть указатель только на родительский класс. Всё. Больше ничего. Какая разница, что там воплощено. Это уже головная боль потомка.

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

Цитата
Ничего не понял. Если у тебя таких массивов миллион, то ф-я всё-равно будет одна.

я наверное криво написал, я имел ввиду, что у каждого массива (а их 100) своя уникальная! обработка. Ну например у массива один мне надо у объектов Pattern навести ракету на цель (т.е. он целится), а у объектов Shape лечить раненых (т.е. оказать медицинскую помощь). В то же время при обработке массива 2 мне надо Pattern произвести выстрел, а Shape окопаться и т.д.. При этом Тип Kate это объект описывающий Unit (у которого есть общие для всех юнитов свойства, показатели здоровья и скорости и т.д.)

Цитата
Цитата
Я чувствую - начали переходить на личности?

Ни в коем случае. Ничего личного.

Полностью поддерживаю.

Цитата
В твоём же случае, речь идёт о ф-ции, которая управляет другими ф-ми, она их вызывает. Что же в этом плохого? Немного другая степень абстракции.

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

Цитата
Классический пример с геометрическими фигурами. Чертить окружность есть совсем не то, что строить треугольник. Но оба они представляют собой некий процесс. Поэтому родительский класс Фигура получает ф-ю Нарисовать(). А уже Треугольники, Квадраты и прочие дети, сами выполняют то, что им нужно.
Если два класса имеют общего предка, то значит их что-то объединяет. Иначе предок не нужен вобще. Поэтому и ф-ции предка, имеют как правило обобщённый смысл. Рисовать, Удалить, Переместить. А "расписание паровозов" и "расчет сметы" всё-таки узкоспециаллизированные задачи. Поэтому они не могут напрямую выполняться какими-то прямыми потомками одного родителя. Как я уже сказал, всё зависит от архитектуры проекта.

Вот в этом и есть наследование поведения! функция рисует или удаляет занимается именно рисованием (удалением соответственно), а вот как она это делает ее личное дело.

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

А вот тут нет. Такого быть не должно, ибо действия принципиально различны.
Записан

С уважением Lapulya
ezus
Опытный

il
Offline Offline

« Ответ #23 : 25-08-2010 18:21 » 

Спасибо, Вы за меня написали практически все мои возражения.
Записан
ezus
Опытный

il
Offline Offline

« Ответ #24 : 25-08-2010 18:44 » 

To Джон.
А какая с Вашей точки зрения должна быть структура объектов в следующей задаче - в соответствием с ООП.
Обработка данных о людях. Естественно у женщин и мужчин есть как много общих данных\функций\алгоритмов, так и исключительно специфических. Мне хотелось бы иметь для них 2 разных класса. Мне кажется очевидным использовать для общих данных и функций базовый класс. Вопрос - как хранить данные о людях, если основная обработка связанна с общими функциями, а специфика проявляется изредка в частных случаях. Например - поликлиника. 80% болячек общие, но иногда необходимо выполнить исключительно женские или мужские проверки. Вести параллельно 2 массива или 1.  А если 1, то как перейти к специфике?
Записан
ezus
Опытный

il
Offline Offline

« Ответ #25 : 25-08-2010 18:50 » 

ну наверное не так
Цитата
Код:
Pattern* ptr = new Pattern;
,а так
Код:
Pattern* ptr = new Pattern();
А в чем разница? Может тут собака порылась.
Записан
ezus
Опытный

il
Offline Offline

« Ответ #26 : 25-08-2010 18:51 » 

.
« Последнее редактирование: 25-08-2010 19:09 от ezus » Записан
ezus
Опытный

il
Offline Offline

« Ответ #27 : 25-08-2010 18:59 » 

Просто раньше я работал в Java, а там таких заморочек не возникало, поэтому я никак не могу проникнуться кишками С++.
Указатель в С++ ~= ссылке (ссылочному типу) в Java, с поправкой на то, что управления временем жизни и сборки мусора нет, а прямая адресация памяти открывает бескрайние просторы для всякого. Соответственно, как указатели ни приводи, объект фактически будет существовать один - тот, который создан, в данном случае, конструкцией new Type; (конструктором по умолчанию на куче). Всё остальное ссылается именно на эту область памяти. И надо не забыть его удалить, т.к., см. выше, сборки мусора нет.
Скорее всего ты прав.
Но в Java это действительно ОДИН объект, и ты просто смотришь на него через разные маски, будь то базовый класс или интерфейсы. Поэтому подобные кастинги естественны и безболезненны. А в С++ похоже не так.
А вот КАК, хотелось бы понять.
Записан
ezus
Опытный

il
Offline Offline

« Ответ #28 : 25-08-2010 19:08 » 

И все-таки может быть кто-нибудь знает - как избежать предупреждения

warning C4541: 'dynamic_cast' used on polymorphic type 'class Keta' with /GR-; unpredictable behavior may result

?
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #29 : 25-08-2010 19:26 » 

lapulya, я "коротко" отвечу, нет ни времени ни желания вдаваться в полемику. Никакого противоречия нет. Я же сказал, примитивненький примерчик. Для начинающих. Поэтому и ф-я называется в всех случаях - Рисуй(). А представь себе, что куча функциональных объектов должна запуститься в определённой последовательности. Например, сбор информации, обработка, вывод результата. Тогда каждый из этих объектов получит ф-ю, например, StartProcess(). И что? Где наследование свойств родителя, и главное - каких? Ага

Конечно же наследование свойств родителя имеет место быть. Например, когда родитель содержит общие для всех деток поля
данных. Тогда и поведение родителя наследуется детьми, например ф-я инициаллизации. Но в таком случае обычно дети сначала вызывают родительскую ф-ю, а потом уже инициаллизируют свои индивидуальные поля данных. В этом случае можно говорить о наследовании свойства родителя - инициаллизации. Но если родитель содержит "чиста" Ага виртуальные (pure virtual) методы, то он автоматически превращается в интерфейс и в этом случае ни о каком вызове "базовых" ф-ций не может быть и речи. В этом случае "наследование свойств родителя" является фиктивным и определяется только семантикой методов: назови метод Сверлить() - и детки уже не смогут Поливать(), а  назови Процесс() - и дашь детям свободу стрелять, окапываться и пр. Ага

Ну примерно в таком аспекте. Хотя, я думаю, это и так ясно.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #30 : 25-08-2010 20:01 » 

To Джон.
А какая с Вашей точки зрения должна быть структура объектов в следующей задаче - в соответствием с ООП.
Обработка данных о людях. Естественно у женщин и мужчин есть как много общих данных\функций\алгоритмов, так и исключительно специфических. Мне хотелось бы иметь для них 2 разных класса. Мне кажется очевидным использовать для общих данных и функций базовый класс. Вопрос - как хранить данные о людях, если основная обработка связанна с общими функциями, а специфика проявляется изредка в частных случаях. Например - поликлиника. 80% болячек общие, но иногда необходимо выполнить исключительно женские или мужские проверки. Вести параллельно 2 массива или 1.  А если 1, то как перейти к специфике?

ezus, немного непривычно - холодно подчёркнутое "Вы", лично мне гораздо приятней дружеское "ты". Но как угодно. Сорри зы "тыканье" в предыдущих постах.

Итак, к Вашему вопросу. Конечно же один массив объектов одного типа - Больные. Совершенно верно - общие поля в базовом классе, а индивидуальные в наследуемых - мужчины, женщины, дети. Например, под индивидуальностью можно назвать посещение врачей - гинеколога, педиатра и "мужолога" (не могу придумать спец. врача для мужуков). Каждого пациета в списке надо отправить к своему врачу. "Вашим" (условно) методом, кажый производный класс получает ф-ю ПосетитьГинеколога(), ПосетитьПедиатра() и тд, потом следует приведение типа (Женщина*), (Ребёнок*) и вызов ф-ции.
Гораздо удобней (также для последующего использования) определить виртуальную ф-ю ПосетитьВрача()=0. Обратите внимание. Физически ничего не изменяется. Каждый объект-наследник получает как и в "Вашем" способе (ещё раз - название чисто условное, чтобы различать) одну специальную ф-ю. Единственно отличие - одна дополнительная строчка в базовом классе. Как видите, никаких лишних ф-ций. Зато какое это даёт преимущество! Допустим, в будущем состав больных придётся расширить. ДОбавяться пожилые, студенты, безнадёжно больные и тп. Как в этом случае будет выглядеть вызов ф-ций в цикле обработки списка? Помните, я привёл пример-объяснение нелепости в #21? И эта "этажерка" вместо одой строчки? Причём надо НЕ ЗАБЫТЬ это сделать!!! В случе с чисто виртуальным методом этого не произойдёт в принципе. Вот и вся "заморочка". Суть остаётся - в цикле обработки списка объектов должно что-то произойти, некое действие. Значит всё сводится к семантике метода, но тут разработчику предоставлена полная свобода выбора.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #31 : 25-08-2010 20:03 » 

И все-таки может быть кто-нибудь знает - как избежать предупреждения

warning C4541: 'dynamic_cast' used on polymorphic type 'class Keta' with /GR-; unpredictable behavior may result

?

Какая ОСь? Какая студия? Тип проекта? Как выполнялись настройки проекта - вручную или приняты по умолчанию?
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #32 : 25-08-2010 20:10 » 

Вот что говорит MSDN

Compiler Warning (level 1) C4541
'identifier' used on polymorphic type 'type' with /GR-; unpredictable behavior may result

You tried to use a feature that requires run-time type information without enabling run-time type information. Recompile with /GR.

Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #33 : 25-08-2010 21:41 » 

Цитата: ezus
Я же отметил, что это ПРИНЦИПИАЛЬНО разные функции, и объединять их под общим именем не вижу никакого смысла, кроме чисто программистских заморочек, которых всегда старался избегать.
Цитата: Джон
Если имя ф-ции как заноза в глазу, назови её CallSpecialFunction() и тогда
Джон совершенно правильно намекает на такой шаблон проектирования, как Command.

Цитата: lapulya
Джон, ezus правильно говорит, нельзя так делать, если следовать твоему предложению, то:
1. Это уже не наследование по логике (наследуемые классы наследуют поведение предка, а тут сразу нарушение этого правила)
Здесь нет наследования, здесь обобщение - просто желание ослабить типизацию, чтобы впихнуть разное в общий массив. По твоей логике абстрактные методы (или "pure virtual", как их в C++ называют) бесполезны, ибо от них нечего наследовать. Издержки языка со статической типизацией, к коим относится C++.

Цитата: lapulya
2. Так можно решить только частную задачу, ну например, у меня таких массивов 100 штук и в каждом из них должна быть разная обработка объектов в зависимости от типа, чтож мне миллион функций в эти классы впихать, чтоб при любой обработке вызвать одну, но виртуальную?
Для этого человечество изобрело такие шаблоны, как Command, Strategy и Bridge Улыбаюсь

Цитата: Джон
преобразование родительского типа к конкретному. Любое такое преобразование - проявление анти ООП настроений. Указывет исключительно на слабо продуманную архитектуру.
Как говорится, +1 Улыбаюсь

Цитата: ezus
warning C4541: 'dynamic_cast' used on polymorphic type 'class Keta' with /GR-; unpredictable behavior may result
В настройках проекта убери ключ /GR-.

Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #34 : 25-08-2010 23:01 » 

Dimka,
Цитата
По твоей логике абстрактные методы (или "pure virtual", как их в C++ называют) бесполезны, ибо от них нечего наследовать.
Под поведением я не имел ввиду реализацию, поэтому чисто она виртуальная в базовом классе или не чисто разницы нет.

Цитата
Для этого человечество изобрело такие шаблоны, как Command, Strategy и Bridge

да кто спорит? Я лишь сказал, что плодить (именно плодить) подобные предложенной Джоном функции - не вариант, они спасают лишь от очень узкой проблемы (обработка конкретного списка в конкретном месте)

Понимаю, что все останутся при своих, но:
пример с врачами мог бы быть не совсем таким простым (хотя вариант с юнитами нагляднее дискредитирует предложенный Джоном вариант). Предположим, для женщин есть 2 уникальных врача (гинеколог1 и гинеколог2), и у мужчин тоже 2 уникальных (ну там... логопед1 и логопед2). Для каждого врача (это абстракция, т.е. чисто для примера) у классов М и Ж есть своя функция (если они одинаковые, то она еще есть и в базовом как виртуальная). Естественно, что разные врачи (гинеколог1, гинеколог2, логопед1 и логопед2 это разные врачи) лечат разные болезни с разными симптомами, а вот педиатор и М и Ж лечит одинаково и симтомы болезни одинаковы.  При этом имеется общий список, в котором и мужчины и женщины. Надо в конкретном обработчике списка (а список может быть не один + обработчиков, что более реалистично, так же не один) исходя из каких-то внешних данных (ввод руками или берем из карты) вызвать у объекта списка нужную функцию (или не вызывать ничего, женские болезни имеют по отношению с мужчинами уникальные симтомы). Представь, что будет если задача будет решаться введением в базовый класс общих методов (и главное сколько их там надо добавить!!!) : f1 (для гинеколог1 для женщин, а для мужчин она будет пустая) и т.д. еще 3 функции (одна для Ж и 2 для М)... ИМХО - утопия. Рабочий вариант - разные списки для М и Ж или каст... да, да если сигнатура функций одинакова, можно обойтись малой кровью (шаблонами), а если нет... при данной архитектуре ппц.
Записан

С уважением Lapulya
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #35 : 25-08-2010 23:01 » 

Пусть есть исходные классы (не обсуждаем, какие и зачем они такие).
Код: (C++)
class Keta
{
public:
    virtual void locate() = 0;
    virtual ~Keta() {}
};

class Pattern:
    public Keta
{
public:
    void locate()
    {
        cout << "Pattern.locate" << endl;
    }
    void fp()
    {
        cout << "Pattern.fp" << endl;
    }
};

class Shape:
    public Keta
{
public:
    void locate()
    {
        cout << "Shape.locate" << endl;
    }
    void fs()
    {
        cout << "Shape.fs" << endl;
    }
};

Ставится задача упаковать их в массив и, обходя этот массив, выполнять специфические для каждого элемента действия. Для этого служит шаблон Command.

Кроме того, хочется извлекать из массива хранимые там элементы. Для этого служит шаблон Variant.

Их соединение приводит к решению:
Код: (C++)
class Command
{
public:
    virtual void run() = 0;
    virtual ~Command() {};
};

template<class Item>
class ArrayItem:
    public Command
{
protected:
    Item *item;
public:
    ArrayItem(Item *item):
        item(item)
    {}
    Item *getItem() const
    {
        return this->item;
    }
};

class ArrayItemPattern:
    public ArrayItem<Pattern>
{
public:
    ArrayItemPattern(Pattern *pattern):
        ArrayItem<Pattern>(pattern)
    {}
    void run()
    {
        this->getItem()->fp();
    }
};

class ArrayItemShape:
    public ArrayItem<Shape>
{
public:
    ArrayItemShape(Shape *shape):
        ArrayItem<Shape>(shape)
    {}
    void run()
    {
        this->getItem()->fs();
    }
};
Эта обёрточного типа надстройка никак не покушается на исходные классы и достаточно автономна от них. В принципе она представляет собой вырожденный случай шаблона Bridge, создающего альтернативное, построенное на других принципах дерево тех же самых элементов, образующих две иерархии сразу.

Наконец, для удобства работы мы можем написать специализированный массив из таких элементов.
Код: (C++)
class Array
{
private:
    typedef vector<Command *> _Array;
    _Array array;
public:
    void add(Pattern *pattern)
    {
        this->array.push_back(new ArrayItemPattern(pattern));
    }
    void add(Shape *shape)
    {
        this->array.push_back(new ArrayItemShape(shape));
    }
    int getSize() const
    {
        return this->array.size();
    }
    template<class Type>
    Type *getItemAt(int i)
    {
        if(i < 0 || i >= this->getSize())
        {
            return NULL;
        }
        Type *container = dynamic_cast<Type *>(this->array[i]);
        typedef ArrayItem<Type> Item;
        Item *item = dynamic_cast<Item *>(this->array[i]);
        return item ? item->getItem() : container;
    }
    ~Array()
    {
        for(int i = 0; i < this->getSize(); ++i)
        {
            delete this->array[i];
        }
    }
};
И написать код, который использует всё это решение.
Код:
    Array array;
    array.add(new Pattern());
    array.add(new Shape());
    for(int i = 0; i < array.getSize(); ++i)
    {
// Test 1
Pattern *pattern = array.getItemAt<Pattern>(i);
cout << i << " is " << (pattern ? "" : "not ") <<  "Pattern" << endl;
// Test 2
Shape *shape = array.getItemAt<Shape>(i);
cout << i << " is " << (shape ? "" : "not ") <<  "Shape" << endl;
    }
    // Test 3
    for(int i = 0; i < array.getSize(); ++i)
    {
array.getItemAt<Command>(i)->run();
    }
    // Warning: Not free memory.
на выходе получаем
Код:
0 is Pattern
0 is not Shape
1 is not Pattern
1 is Shape
Pattern.fp
Shape.fs
« Последнее редактирование: 26-08-2010 00:39 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #36 : 25-08-2010 23:04 » 

Цитата: lapulya
пример с врачами мог бы быть не совсем таким простым (хотя вариант с юнитами нагляднее дискредитирует предложенный Джоном вариант). Предположим, для женщин есть 2 уникальных врача (гинеколог1 и гинеколог2), и у мужчин тоже 2 уникальных (ну там... логопед1 и логопед2). Для каждого врача (это абстракция, т.е. чисто для примера) у классов М и Ж есть своя функция (если они одинаковые, то она еще есть и в базовом как виртуальная).
О, для случая хождения по врачам человечество изобрело шаблон Visitor Улыбаюсь
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #37 : 25-08-2010 23:11 » 

дык, я ж об этом и написал, что в самих Pattern, Shape и Keta ничего добавлять не надо. Наоборот, все, что связано с обработкой должно быть венесено (исходные классы достаточны в своем интерфейсе). А вот предложенное димкой решение и есть архитектурное решение проблемы (оно общее, т.к. не затрагивает самих Pattern, Shape и Keta). Тут я полностью согласен с Димкой.

Визитор из той же бочки.

Тут нет (и не будет такого), что функция расчета ведомости печатает расписание поездов.
« Последнее редактирование: 25-08-2010 23:14 от lapulya » Записан

С уважением Lapulya
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #38 : 26-08-2010 04:57 » 

и в чём проблема?
Код:
class IHuman
{
public:
    virtual ~IHuman() = 0;
   
    virtual void GoToDoctor() = 0;
    virtual void DoSomeThingVerySpecialOnEachOperation() = 0;
};

class TAdult : public IHuman
{
public:
    ~TAdult(){;}
    virtual void GoToDoctor()
    {
        GoToDoctor1();
        GoToDoctor2();
        GoToDoctor3();
    }
private:
    void GoToDoctor1();
    void GoToDoctor2();
    void GoToDoctor3();   
};


class TAdultMan : public TAdult
{
public:
    TAdultMan(){;}
    virtual void GoToDoctor()
    {
        Adult::GoToDoctor();
        GoToDoctor3();
    }
private:
    void GoToDoctor3();   
};

class TAdultWoman : public TAdult
{
public:
    TAdultWoman(){;}
    virtual void GoToDoctor()
    {
        Adult::GoToDoctor();
        GoToDoctor4();
    }
private:
    void GoToDoctor4();   
};

typedef std::vector<IHuman> TPatients;
typedef TPatients::iterator TPatientsIter;

void ProcessAll(TPatients & data)
{
    for (TPatientsIter it = data.begin(); it != data.end(); ++it)
    {
        it->GoToDoctor();
        it->DoSomeThingVerySpecialOnEachOperation();
    }
}
Записан

Странно всё это....
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #39 : 26-08-2010 06:33 » 

Я лишь сказал, что плодить (именно плодить) подобные предложенной Джоном функции - не вариант, они спасают лишь от очень узкой проблемы (обработка конкретного списка в конкретном месте)

Да где плодить-то? Ведь ф-ции у "детей" и так существуют. Единственное, что добавится/изменится - это название ф-ции и виртуальный метод в родителе/интерфейсе.

Цитата
Понимаю, что все останутся при своих

Я тоже это понимаю, поэтому никакого желания пытаться сделать мир лучше. Ага

ps ИМХО получился небольшой флуд с отклонением от основной темы, в котором вопросы ezus-а легко теряются. Стоит ли его выделить в отдельную тему? Тема-то, похоже, вечная. Есть смысл её продолжать?
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
ezus
Опытный

il
Offline Offline

« Ответ #40 : 26-08-2010 07:09 » 

Стоит ли его выделить в отдельную тему? Тема-то, похоже, вечная. Есть смысл её продолжать?
Я думаю не стоит - тема действительно вечная, и скорее всего каждый останется при своих, хотя и с немного расширенным кругозором, что, конечно, тоже не вредно.

Всем СПАСИБО.
Я получил исчерпывающие ответы на все мои вопросы.

P.S. По поводу "ВЫ\ТЫ".
Это просто мое древнее воспитание, с которым я борюсь. Поэтому мое "ВЫ" ни к сарказму, ни к неувожению отношения не имеет. Обещаю в следующий раз постараться сразу начинать с "ТЫ".
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #41 : 26-08-2010 07:23 » 

Да, не, я и не подумал про сарказм и пр. Да и воспитание штука хорошая. Просто с друзьями как-то всё больше на "ты". Ага
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #42 : 26-08-2010 11:00 » 

Антон (LogRus),
))))))) бугага... ты меня не понял... когда у человека что-то болит его не посылают ко всем врачам сразу, а посылают к конкретному, суть вот в чем (причем Димка описал концепцию  решения).

Код:
class Human
{
  ...
  virtual void GoToDoctor1() = 0; // тут можно убрать чисто вирт. и написать реализацию... не суть.
  virtual void GoToDoctor2() = 0; // тут можно убрать чисто вирт. и написать реализацию... не суть.
  virtual void GoToDoctor3() = 0; // тут можно убрать чисто вирт. и написать реализацию... не суть.
}

class Man : public Human
{
  ...
  void GoTo_MAN_Doctor1() {}
  void GoTo_MAN_Doctor2() {}
}

class Woman : public Human
{
  ...
  void GoTo_WOMAN_Doctor1() {}
  void GoTo_WOMAN_Doctor2() {}
}

typedef std::vector<IHuman> TPatients;
typedef TPatients::iterator TPatientsIter;

void ProcessAll(TPatients & data, Симптом & симптом)
{
    for (TPatientsIter it = data.begin(); it != data.end(); ++it)
    {
        if (симптом == 1)
            it->GoToDoctor1();  // это вирт. функция предка по общему врачу для М и Ж по одинаковым симптомам
        else if (симптом == 2)
            it->GoToDoctor2();  // это вирт. функция предка по общему врачу для М и Ж по одинаковым симптомам
        else if (симптом == 3)
            it->GoToDoctor3();  // это вирт. функция предка по общему врачу для М и Ж по одинаковым симптомам

        else if (симптом == ЧИСТА_КАНКРЕТНА_ЖЕНСКИЙ_СИМПТОМ1)
            ??????????;
        else if (симптом == ЧИСТА_КАНКРЕТНА_ЖЕНСКИЙ_СИМПТОМ2)
            ??????????;
        else if (симптом == ЧИСТА_КАНКРЕТНА_МУЖСКОЙ_СИМПТОМ1)
            ??????????;
        else if (симптом == ЧИСТА_КАНКРЕТНА_МУЖСКОЙ_СИМПТОМ2)
            ??????????;
    }
}

Цитата
Да где плодить-то? Ведь ф-ции у "детей" и так существуют. Единственное, что добавится/изменится - это название ф-ции и виртуальный метод в родителе/интерфейсе.
Нееее надо будет именно плодить, ибо одной функции будет мало
« Последнее редактирование: 26-08-2010 11:09 от lapulya » Записан

С уважением Lapulya
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #43 : 26-08-2010 15:33 » 

Далась вам эта архитектура Улыбаюсь. Вопрос к C++ отношения не имеет.

В отечественных поликлиниках до сих пор есть такое явление, как "участковый терапевт", а местами для людей состоятельных - "личный лечащий врач". Именно он решает, к каким специалистам и с какой целью направлять пациента, а также когда выдавать больничный, выписывать и т.д.

Решения о конкретном специалисте терапевт принимает, основываясь на симптомах, поле и возрасте пациента.

Поэтому разумно врачей поделить на специалистов и "врача по умолчанию". Для пациента завести список направлений с перечнем врачей, которых ему нужно посетить.

Каждый врач может определить, к нему данный пациент или нет.

Получается такое решение:
Код: (Ruby)
# Пациент
class Patient
 
  # Пол
  Male = 0
  Female = 1
 
  def initialize(name, birth_year, sex)
    @name = name
    @birth_year = birth_year
    @sex = sex
    @doctors_list = Array.new
  end
 
  attr_reader :name, :sex

  def age
    # Примерный возраст
    return Time.now.year - @birth_year
  end

  # Получает направление к врачу
  def assign(doctor)
    puts "#{self.name} получил направление к #{doctor.name}"
    if not @doctors_list.include? doctor then
      @doctors_list.push doctor
    end
  end

  # Проходит курс лечения
  def medical_treatment
    while not @doctors_list.empty?
      doctor = @doctors_list.shift
      doctor.receive self
    end
  end

end

# Абстрактный врач
class Doctor

  attr_reader :name

  def receive(patient)
    # Приём пациента
    puts "#{self.name} принял #{patient.name}"
  end

  def accept?(patient)
    # Принимает любых пациентов
    return true
  end

end

class Physician < Doctor

  def initialize(specialists)
    @name = "Терапевт"
    @specialists = specialists
  end

  def receive(patient)
    super patient
    # Назначает всех подходящих специалистов
    for specialist in @specialists
      if specialist.accept? patient then
        patient.assign specialist
      end
    end
  end

end

class Pediatrician < Doctor

  def initialize
    @name = "Педиатр"
  end

  def accept?(patient)
    # Принимает пациентов до 14 лет
    return patient.age < 14
  end

end

class Surgeon < Doctor

  def initialize
    @name = "Хирург"
  end

end

class Gynaecologist < Doctor

  def initialize
    @name = "Гинеколог"
  end

  # Принимает женщин
  def accept?(patient)
    return patient.sex == Patient::Female
  end

end

patients =
  [
    Patient.new("Ваня", 2003, Patient::Male) ,
    Patient.new("Василий Петрович", 1938, Patient::Male) ,
    Patient.new("Елена", 1992, Patient::Female)
  ]

specialists =
  [
    Pediatrician.new,
    Surgeon.new,
    Gynaecologist.new
  ]

physician = Physician.new specialists

for patient in patients
  physician.receive patient
end

for patient in patients
  patient.medical_treatment
end
Результаты работы:
Код:
Терапевт принял Ваня
Ваня получил направление к Педиатр
Ваня получил направление к Хирург
Терапевт принял Василий Петрович
Василий Петрович получил направление к Хирург
Терапевт принял Елена
Елена получил направление к Хирург
Елена получил направление к Гинеколог
Педиатр принял Ваня
Хирург принял Ваня
Хирург принял Василий Петрович
Хирург принял Елена
Гинеколог принял Елена
Как-то так...
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #44 : 26-08-2010 16:23 » 

Антон (LogRus),
))))))) бугага...

всё это чушь и отношения к делу не имеет, можно сколь угодно строить теории и прочее, но они хороши в конкретном практическом приложении, а это приложение есть у автора темы Улыбаюсь


Dimka, если мы решаем проблему докторов и пациентов, то твое решение мне больше нравится, но бывают и другие задачи Улыбаюсь

похоже тема действительно себя исчерпала
Записан

Странно всё это....
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #45 : 27-08-2010 06:51 » 

похоже тема действительно себя исчерпала

Ага, ещё в зародыше.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Страниц: 1 2 [Все]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines