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

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

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

« : 19-02-2006 00:09 » 

Начну наверное с кода
class_line.h
Код:
#include "stdafx.h"

namespace CLine_sp
{
struct PointInfo
 {
int NumPoints;
int **APoints;
 
 };
class CLine
{
protected:
int **APoints;
int NumPoints;

public:
CLine();
virtual   bool Approximate()=0;
 void NewPoint(int x, int y);
 void GetPointInfo(PointInfo* PInfo);
~CLine();


};
/////////////////////////
class CBezye: public CLine
{
public:
bool Approximate();

};

class CLagranj:public CLine
{
public:
bool Approximate();
};

}
class_line.cpp
Код:

#include "stdafx.h"
#include "class_line.h"

namespace CLine_sp
{
 
CLine::CLine()
{
NumPoints=0;
APoints=NULL;
}

CLine::~CLine()
{
if(NumPoints>0)
{
delete (*APoints);
        delete (APoints);
}

}


void CLine::NewPoint(int x, int y)
{
  int **temp=NULL;
  int i=0;
if(NumPoints>0)
  {

//int ::**temp=NULL;
temp=new int* [2];
temp[0]=new int [NumPoints];
temp[1]=new int [NumPoints];

              for( i=0;i<NumPoints;i++)
              {
                temp[0][i]=APoints[0][i];
            temp[1][i]=APoints[1][i];
              }
   
                              delete(*APoints);
                        delete (APoints);
                                    APoints=NULL;
  }

        APoints=new int* [2];
APoints[0]=new int[++NumPoints];
APoints[1]=new int[NumPoints];

                                                    for(i=0; i<NumPoints-1;i++)
{
APoints[0][i]=temp[0][i];
APoints[1][i]=temp[1][i];
}
      APoints[0][NumPoints-1]=x;
  APoints[1][NumPoints-1]=y;

                    if(NumPoints>1)
{delete (*temp);
delete (temp);}

}
void CLine::GetPointInfo(PointInfo* PInfo)
   {
   PInfo->NumPoints=NumPoints;
   PInfo->APoints=APoints;
   }

   
   bool CBezye::Approximate()
   {
   MessageBox(NULL,"bezye","",0);
   char s[5];
   itoa(NumPoints,s,10);
   MessageBox(NULL,s,"NumPoints",0);
   return true;
   }

   bool CLagranj::Approximate()
   {
    MessageBox(NULL,"lagranj","",0);
   return true;
   }
}
1.cpp
Код:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
using namespace CLine_sp;
static CLine  *obj_line, line;
static CBezye  bezye;
// static
int i=0;

PointInfo PInfo;
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;

switch (message)
{
  case WM_CREATE:
    obj_line=&line;
break;

case WM_COMMAND:
wmId    = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;

case ID_APPROXIMATE_BEZYE:
            {
    obj_line=&bezye;
((CBezye *)obj_line)->Approximate();
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_LBUTTONDOWN:
     
   obj_line->NewPoint(LOWORD(lParam),HIWORD(lParam));
   InvalidateRect(hWnd,NULL,true);


break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...

obj_line->GetPointInfo(&PInfo);
    for( i=0;i<PInfo.NumPoints;i++)
{
SetPixel(hdc,PInfo.APoints[0][i],PInfo.APoints[1][i],0xAA);
SetPixel(hdc,PInfo.APoints[0][i]+1,PInfo.APoints[1][i],0xAA);
SetPixel(hdc,PInfo.APoints[0][i]-1,PInfo.APoints[1][i],0xAA);
SetPixel(hdc,PInfo.APoints[0][i],PInfo.APoints[1][i]+1,0xAA);
SetPixel(hdc,PInfo.APoints[0][i],PInfo.APoints[1][i]-1,0xAA);
SetPixel(hdc,PInfo.APoints[0][i]+1,PInfo.APoints[1][i]+1,0xAA);
SetPixel(hdc,PInfo.APoints[0][i]-1,PInfo.APoints[1][i]+1,0xAA);
SetPixel(hdc,PInfo.APoints[0][i]-1,PInfo.APoints[1][i]-1,0xAA);
SetPixel(hdc,PInfo.APoints[0][i]+1,PInfo.APoints[1][i]-1,0xAA);
}
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
obj_line=NULL;
delete (obj_line);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Теперь постараюсь пояснить. Хочу сразу предупредить, что прблемы созданные здесь, созданы с целью повышения знаний по ООП.
И так.
Программа должна выполнять построение кривых двумя методами - Безье и Лагранжа.
Для построения кривой по методу Безье должен (по моей задумке) использоваться метод bool Approximation() класса CBezye, по методу Лагранжа - метод bool Approximation() класса CLagranj.
Пользователь ставит точки по которым и будет производится построение, значение координат заносится в массив APoints. В переменной NumPoints содержится кол-во точек.
Заранее неизвестно каким именно методом пользователь захочет строить эти кривые.
Можно было бы сделать так, чтобы в каждом классе (CBezye и СLagranj) содержался свой массив APoints. Но в них ведь будут содержаться одинаковые значения, к тому же хотелось бы использовать преимущества ООП, поэтому я хотел бы сделать что-то вроде следующего.
В родительском классе CLine содержится массив APoints. А метод Approximation() классов CBezye и CLagranj могли бы использовать значения массива APoints. Только я не знаю как бы это все првильно сделать. Т.е. я хотел бы чтобы было прмерно так:
занесли в APoints значения
СLine *obj->NewPoints()
А затем вызываю метод Approximation либо класса CBezye либо СLagranj, который мог бы использовать значения APoints.

В том, что я сейчас навоял есть следующее:
В WM_CREATE создается объект класса-родителя СLine
В WM_LBUTTONDOWN происходит заполнение массива
В WM_PAINT происходит вывод точек.

А вот затем, я хотел бы, чтобы при обработки нажатия меню произошло примерно следующее
CBezye obj;
obj.Approximation()

Но только, как я понимаю (да вроде так и происходит) объект obj не располагает значениями, которые заносились до этогот через объект класса CLine.
Как  же мне провернуть эту затею?

« Последнее редактирование: 19-02-2006 00:18 от nikedeforest » Записан

ещё один вопрос ...
Alf
Гость
« Ответ #1 : 19-02-2006 00:26 » 

Все разом, само собой, ниасилил, нужно тщательно вчитываться. Пока при поверхностном чтении возникло два замечания:

1. В самом начале программы объявлена структура PointInfo, а затем в классе CLine объявлены такие же члены-переменные. Почему бы не агрегировать структуру в класс, раз уж все равно объявлена?

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

А вообще в таких случаях гораздо лучше нарисовать диаграмму классов. На ней все видно нагляднее, не нужно вчитываться в исходный текст, да и не зависит от языка реализации.
Записан
nikedeforest
Команда клуба

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

« Ответ #2 : 19-02-2006 00:31 » 

Про пункт 2 я в курсе, просто сейчас экспериментирую Ага.
Про пункт 1, я так никогда не делал, сейчас попробую.
Цитата
А вообще в таких случаях гораздо лучше нарисовать диаграмму классов. На ней все видно нагляднее, не нужно вчитываться в исходный текст, да и не зависит от языка реализации.
Ну а суть того, что я хочу понятна? Я старался словесно все расписать, чтобы в код всматриваться даже не пришлось. Код кинул на всякий случай.
Alf, я диаграммы классво никогда не рисовал. Структурные схемы рисовал Улыбаюсь.
Диаграммы рисуются с помощью UML?
Записан

ещё один вопрос ...
Alf
Гость
« Ответ #3 : 19-02-2006 00:46 » 

Alf, я диаграммы классво никогда не рисовал. Структурные схемы рисовал Улыбаюсь.
Диаграммы рисуются с помощью UML?

Да, в данном случае речь идет о статической диаграмме классов. Очень простая и наглядная картинка, суть схватываешь сразу, не влазя в дебри описаний.

А теперь еще замечания.

3. Насколько я понял, назначение структуры PointInfo таково: она содержит счетчик точек, образующих ломаную, и указатель на массив координат этих точек.

Если это так и есть, это никуда не годится. Дело в том, что в структуре все члены открыты, поэтому нет никакой гарантии, что количество элементов массива в точности совпадает со значением счетчика. А если в какой-то момент и совпадает, то нет гарантии, что это хрупкое равновесие не будет нарушено глупой ошибкой в программе. Например, если ты по ошибке напишешь
Код:
NumPoints = 0;
,
то твой деструктор уже никогда не уничтожит массив, даже если там миллион точек.

Вывод: для хранения списка точек нужно создать отдельный класс, а не структуру. Кроме того, список точек лучше хранить не в массиве, а в каком-либо контейнере, который может динамически менять размер. Это позволит на ходу легко добавлять и убирать точки.

4. Саму точку тоже лучше сделать классом, а не массивом из двух чисел. Тем более вдруг завтра тебе заблагорассудится строить кривые не на плоскости, а в пространстве?..

5. Ты заранее не можешь знать, что выберет пользователь - Кривую Безье или Лагранжа. Раз так, создавай их динамически через вызов new, а не заготавливай впрок, авось пригодится. Тем более что арсенал кривых может впоследствии расшириться.

Вот пока информация к размышлению...
« Последнее редактирование: 19-02-2006 00:50 от Alf » Записан
nikedeforest
Команда клуба

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

« Ответ #4 : 19-02-2006 01:03 » 

Цитата
Вывод: для хранения списка точек нужно создать отдельный класс, а не структуру. Кроме того, список точек лучше хранить не в массиве, а в каком-либо контейнере, который может динамически менять размер. Это позволит на ходу легко добавлять и убирать точки.
По контейнер понятно все, все никак не приучу себя к STL (вроде бы и удобно, а все равно что-то во мне противится этому Улыбаюсь, ну да ладно это я осилю ).
Класс для точки вместо структуры - это по сути будет тажк структура только более защищенная. Я так понял? Т.е. там будет контейнер, счетчик, методы Get и Set. Правильно?
По пункту 4 не совсем понял. По идеи то, что ты советуешь в пункте 3 будет ведь содержать массив (контейнер) точек, зачем мне класс для отдельной точки? Или я не так понял?
По пункту 5.
Ты имеешь ввиду
CBezye *obj;
obj=new CBezye;  ?
Если да, то я согласен на все 100%.

Меня все же интересует из любопытсва. Если не вносить изменения в программу о которых ты говорил, как же все-таки сделать то что я хотел?
По сути ведь я хочу сделать что-то типа этого:
Код:
СLine *obj=new CLine;
obj->NewPoints(x,y); // заносим значения в массив
((СBezye*)obj)->Approximation();
Кстати я так еще не пробовал, но по идеи не должно сработать, этим кодом я просто пытался пояснить что я хочу сделать (научиться делать).
P.S.
 я конечно сделаю изменения о которых ты говоришь, но мне все таки очень хочется найти ответ на мой вопрос.
« Последнее редактирование: 19-02-2006 01:06 от nikedeforest » Записан

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

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

« Ответ #5 : 19-02-2006 01:13 » 

А вы ещё не спите? Улыбаюсь

nikedeforest, у тебя книжка есть по ООП? "Надо приобресть" (с) Alf, в 5ом пункте говорит о полиморфизме, и он уже сказал, что CLine абстрактный класс.
Всё что требуется:

CLine *obj = new CBezye;
или
CLine *obj = new CLagranj;

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

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"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."
nikedeforest
Команда клуба

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

« Ответ #6 : 19-02-2006 01:16 » 

Народ, тот код, что я написал оказывается работает Улыбаюсь.
Обалдеть Улыбаюсь, как сразу не доехал.
Записан

ещё один вопрос ...
Alf
Гость
« Ответ #7 : 19-02-2006 01:16 » 

По контейнер понятно все, все никак не приучу себя к STL (вроде бы и удобно, а все равно что-то во мне противится этому Улыбаюсь, ну да ладно это я осилю ).

Без этого добавление/удаление точек превратится в кошмар.

Класс для точки вместо структуры - это по сути будет тажк структура только более защищенная. Я так понял? Т.е. там будет контейнер, счетчик, методы Get и Set. Правильно?

Не совсем. Речь пока идет об одной точке, контейнер здесь не потребуется. Контейнер нужен там, где у нас список точек, то есть - прямая.

По пункту 4 не совсем понял. По идеи то, что ты советуешь в пункте 3 будет ведь содержать массив (контейнер) точек, зачем мне класс для отдельной точки? Или я не так понял?

См предыдущий пункт.

По пункту 5.
Ты имеешь ввиду
CBezye *obj;
obj=new CBezye;  ?
Если да, то я согласен на все 100%.

Немного не так. Более гибкий вариант:

Код:
CLine *obj;
...
if (выбрана кривая Безье)
  obj = new CBesier(...);
else if (выбрана кривая Лагранжа)
  obj = new CLagrange(...);
...

То есть задействовать полиморфизм. Наш указатель имеет тип указателя на родительский класс,  а фактически указывает на один из производных, выбранных динамически в процессе выполнения программы. Механизм динамической диспетчеризации сам выберет впоследствии, какие виртуальные функции будут вызваны при разыменовании указателя.
Записан
Alf
Гость
« Ответ #8 : 19-02-2006 01:29 » 

Вот набросал эскиз диаграммы классов для программы:



Как видишь, каритнка компактная, но из нее видно абсолютно все.

* Line.gif (6.99 Кб - загружено 2103 раз.)
Записан
Olegator
Команда клуба

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

« Ответ #9 : 19-02-2006 01:36 » 

Alf, на чём ты её сделал?
Чем отличается ромбик от стрелочки?
Зачем нужна единица и точка?
Записан
nikedeforest
Команда клуба

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

« Ответ #10 : 19-02-2006 01:38 » 

Джон, я же выше написал, чтобы на virtual bool Approximation()=0;
не обращали внимание - это я так экспериментирую тут у себя и тем самым я делал намек, что рассматриваю как вариант абстрактного родительского класса, так и не абстрактного.
В конечном итоге у меня сейчас родительский класс не абстрактный, т.е. строчку
virtual bool Approximation()=0; я откинул.
А затею я реализовал так, как написал в конце четвертого поста этой темы.
А книга по ООП у меня есть Улыбаюсь.



Записан

ещё один вопрос ...
nikedeforest
Команда клуба

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

« Ответ #11 : 19-02-2006 01:40 » 

Alf, я так понимаю, что контейнер точек будет храниться в классе CLine?
Записан

ещё один вопрос ...
Alf
Гость
« Ответ #12 : 19-02-2006 01:48 » 

На всякий случай небольшой экскурс по диаграмме классов для тех, кто раньше не имел дело с UML.

1. Каждый класс представляется в виде прямоугольника, разделенного на 3 части.

2. В верхней части записывается имя класса.

3. В средней части перечислены переменные класса.

4. В нижней части перечислены методы класса.

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

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

7. Для переменных указывается тип, для методов - типы формальных параметров и возвращаемого значения (если есть).

8. Перед каждым членом класса указывается один из атрибутов видимости:
  - - private;
  + - public;
  # - protected.

9. Линия с ромбиком на одном конце означает отношение агрегации, т.е. класс на той стороне, где ромб, включает в себя какое-то количество экземпляров класса на другой конце линии. Количество экземпляров указывается на концах связи (* - произвольное количество). В данном случае агрегат указывает, что Линия может включать в себя произвольное количество Точек.

10. Линия с незакрашенной стрелкой на конце указывает на отношение наследования между классами, при этом стрелка указывает в направлении от производного класса к базовому.

Вот так вкратце читается диаграмма классов UML. Конечно, есть масса нюансов, но в качестве первого приближения пойдет.
Записан
Alf
Гость
« Ответ #13 : 19-02-2006 01:55 » 

Alf, на чём ты её сделал?

MS Visio Professional 2003. Не лучший вариант, но когда нужно лишь проиллюстрировать идею, не разрабатывая вглубь, вполне годится. Для серьезных применений использую XDE от Rational Software.

Чем отличается ромбик от стрелочки?

См. выше.

Зачем нужна единица и точка?

Цифры и символы на концах отношения агрегирования указывают "мощность" данного отношения. В данном случае это значит следующее. Единица со стороны класса Line указывает, что каждая точка может принадлежать только одной линии. Звездочка со стороны класса Point указывает, что линия может состоять из произвольного количества точеек (включая нуль).
Записан
Alf
Гость
« Ответ #14 : 19-02-2006 01:57 » 

Alf, я так понимаю, что контейнер точек будет храниться в классе CLine?

Правильно. Вообще хорошо спроектированная ОО программа должна представлять собой модель предметной области, для которой она написана. Каждая сущность предметной области должна быть отражена соответствующим классом. В данном случае мы говорим, что линия состоит из набора точек, что вполне соответствует действительности.
Записан
Olegator
Команда клуба

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

« Ответ #15 : 19-02-2006 01:59 » 

Единица со стороны класса Line указывает, что каждая точка может принадлежать только одной линии.
Почему так сделали? Почему не сделать так, чтобы одна точка могла принадлежать многим линиям?
« Последнее редактирование: 19-02-2006 02:03 от Olegator » Записан
Alf
Гость
« Ответ #16 : 19-02-2006 02:04 » 

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

Вообще при программировании нужно придерживаться необходимого минимализма - если задача решается просто, ни к чему добавлять искусственные сложности, которые не приносят реальной пользы.
Записан
Джон
просто
Администратор

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

« Ответ #17 : 19-02-2006 12:38 » 

В конечном итоге у меня сейчас родительский класс не абстрактный, т.е. строчку
virtual bool Approximation()=0; я откинул.

Зря, в первом случае ты сделал всё абсолютно правильно, именно так и должно быть. Общие данные в родительском классе и различные операции обработки или использования этих данных в дочерних классах. Потом, почему "рисование" у тебя присходит в WndProc? Не лучше ли объекту поручить эту задачу? По ООПшному у тебя реакция на WM_PAINT должно выглядеть примерно так:

Код:
case WM_PAINT:
HDC hdc = BeginPaint(hWnd, &ps);
obj->Draw(hdc);
EndPaint(hWnd, &ps);

Ну и так далее.

Просто замечание, а не проще ли начать исследование ООП с чего-нибудь попроще? Кривые Безье сами по себе вещь не тривиальная. Сделай сначала простые геометрические фигуры - линия, прямоугольник, круг, треугольник с родительским классом, например, CFigure и набором функций. Для "количества" достаточно будет простого массива указателей на CFigure. "Усвой" полиморфизм. Не надо отвлекаться на STL и сложные формулы, которые к ООП никакого отношения не имеют (хотя по большому счёту надо бы с этого начать, как с основных структур, зачем тебе сразу STL? Сделай для начала, например, свой собственный связаный список, потом можно сделать из него шаблон - после этого ты поймёшь проблематику и будешь знать на что такие структуры способны, что они могут делать. После этого и STL будет просто хорошей библиотекой, а не чёрным ящиком).

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

Alf, как там было в Матане: "необходимо и достаточно"? Улыбаюсь

nikedeforest, если ты ставишь задачу усвоить получше ООП, то не надо вводить дополнительные сложности и непонятности, загромождать всё дополнительным кодом, необязательным для выполнения основной задачи. Вообще то самыми хорошими классами для начала изучения ООП ИМХО являются Дробь и Строка. Перегрузка операторов, функций, инкапсуляция данных. И только потом переходить к наследованию, полиморфизму.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"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
Пол: Мужской

« Ответ #18 : 19-02-2006 12:49 » 

Просто разбил на два поста - теперь ближе к телу Ага

А затею я реализовал так, как написал в конце четвертого поста этой темы.

А как именно? По идее ты всё делал правильно и CLine абстрактный, и "желание" у тебя было правильным.

Код:
СLine *obj=new CLine;
obj->NewPoints(x,y); // заносим значения в массив
((СBezye*)obj)->Approximation();

только это должно так выглядеть:

Код:
СLine *obj=NULL;
if(пользователь выбирает Безье)
   obj = new CBezye;
else
   obj = new CLagranj;

obj->NewPoints(x,y);
obj->Approximation();
obj->Draw();
...
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"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."
nikedeforest
Команда клуба

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

« Ответ #19 : 19-02-2006 14:06 » 

Джон, вот почти рядом. Сейчас по идеи уже будет проще нам общаться.
Я понимаю, что правильно - делать абстрактный класс, но как вы все справедливо заметили, нельзя создать объект абстрактного класса.
Я понимаю, что вы (Джон, Альф) мне говорите, но мне кажется вы не все совсем поняли, что у меня к чему.
Я вот как думал сделать:
Запускается программа и создается объект родительского класса, т.е. CLine *obj=new CLine;
Потом пользователь на рабочей области окна щелкает мышкей тем самым назначая контрольные точки. Функция NewPoints() всего навсего заполняет массив тех самых контрольных точек. Т.е. пользователь щелкнул по области окна и координаты щелчка занеслись в массив. Пользователь поставит таких точек всего 3-4 (на желание).
После того, как пользователь поставил эти контрольные точки он решает с помощью какого алгоритма будет строится кривая, либо методом Безье, либо методом Лагранжа. Заострите здесь внимание пожалуйста. Сначала ставим точки и только потом решаем каким алгоритмом строить.

Если делать как предлагаете вы (это конечно верно с точки зрения ООП), то пользователь сначала должен выбрать алгоритм построения кривой и только потом он будет ставить контрольные точки. Так ведь получается?
Если же делать как вы, но реализовывать то, что я запланировал, то здесь 2 варианта:
1) Создать глобальный массив этих контрольных точек. Когда пользователь будет ставить контрольные точки, то будет заполняться глобальный массив. Затем, когда пользователь выберет алгоритм, то как раз  тогда создастся объект нужного дочернего класса и в него уже надо будет передать этот массив контрольных точек.
2)Сразу создать 2 объекта (по одному для каждого дочернего класса). Когда пользователь будет ставить контрольные точки, то для каждого объекта производить заполнение массива контрольных точек.
Теперь должно многое проясниться. Мне ведь как раз интересно унать как сделать так, чтобы все объекты дочерних классов располагали одним на всех массивом APoints. Понимаете? Это, думаю, можно было бы достичь, сделав массив APoints статическим (static). Я прав? Если да, то хорошо, но можно ли сделать по-другому?
Я пока вот как делаю:
Код:
class CLine
{
protected:
int **APoints;
int NumPoints;

public:
CLine();

 void NewPoint(int x, int y);
 void GetPointInfo(PointInfo* PInfo);
~CLine();


};
/////////////////////////
class CBezye: public CLine
{
public:
bool Approximate();

};

class CLagranj:public CLine
{
public:
bool Approximate();
};
Описание методов приводить не буду, думаю не в этом соль. Приведу как дальше работаю с классами.
Код:
CLine  *obj_line, line;
obj_line=&line;
obj_line->NewPoint(LOWORD(lParam),HIWORD(lParam));

         if(пользователь выбирает Безье)
         ((CBezye *)obj_line)->Approximate();
         else
         ((CLagranje*)obj_line)->Approximate();

Ну теперь, думаю вам должно стать совсем понятно Ага (иначе я уж и не знаю как объяснить)
Вы поймите, я хочу достичь следующего:
-пользователь сначала ставит точки и только потом выбирает алгоритм построения
-не хотелось бы для объекта каждого дочернего класса производить заполнение массива APoints
-не хотелось бы использовать глобальный (или локальный статический) массив, не   принадлежащий классу.
-По сути хочу сделать так, чтобы массив APoints был одинаков для всех дочених классво (млин, наверное static напрашивается)
Как правильно-то сделать, вариантов ведь много, но наилучший должен быть один (на то он и наилучший Ага )
Записан

ещё один вопрос ...
nikedeforest
Команда клуба

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

« Ответ #20 : 19-02-2006 14:24 » 

Тоже решил разбить на 2 поста Ага. Этот пост меньше к делу, в нем я хочу пояснить свои мотивации Улыбаюсь.
Цитата
Просто замечание, а не проще ли начать исследование ООП с чего-нибудь попроще? Кривые Безье сами по себе вещь не тривиальная. Сделай сначала простые геометрические фигуры - линия, прямоугольник, круг, треугольник с родительским классом, например, CFigure и набором функций.
Джон, я ознакомился с теорией по ООП и многое усвоил (я в курсе был про абстрактные классы Ага ), но теория без практики ничего не дает. И вот я начинаю (точнее продолжаю)практиковаться. НО. У меня не так много времени, чтобы выдумать себе задания Жаль и я стараюсь оттачивать свои знания на том, что мне подкидывают. Т.е. я стараюсь совмещать. Это программа по сути легко решается без всякого ООП и я уже давно бы про нее забыл. Но я решил использовать ООП, чтобы было впрок. Надеюсь я найду понимание и не получу упреков типа того, что зачем нагромаждать. Лучше нагромаждать сейчас, пока учусь, чем потом, когда придется работать по специальности Ага (если конечно повезет).
Цитата
Не надо отвлекаться на STL и сложные формулы, которые к ООП никакого отношения не имеют (хотя по большому счёту надо бы с этого начать, как с основных структур, зачем тебе сразу STL?
Вот именно в этой программе я не захотел отвлекаться на STL. Я немного уже поработал с STL и оценил ее (т.е. удобно Улыбаюсь ), но пока для меня работа с STL означает брать книгу и смотреть как там что делать (потому как в памяти еще не отложилось), в данном случае не хотелось отвлекаться.
Вроде бы все. Сильно не пинайте Ага.
 
Записан

ещё один вопрос ...
Михалыч
Команда клуба

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

« Ответ #21 : 19-02-2006 16:53 » 

Пардон, господа, что влезаю Улыбаюсь У вас и так хорошо получается Улыбаюсь Улыбаюсь Но мои 5 копеек так и жгут руку. Так что я их таки закину Улыбаюсь
Мне лично импонирует идея глобального массива точек, м.б. и статического, хотя и не обязательно. И указатель на массив в любом дочернем классе. Во всяком случае я не стал бы заводить сразу 2 объекта дочерних классов и заполнять каждому из них свой массив. Ладно бы еще когда их только 2...3...10. А если их фиг знает сколько - читай очень много? А еще лучше вообще неизвестно сколько. Создавать динамически по мере надобности - мне так кажется Улыбаюсь
Цитата
не хотелось бы использовать глобальный (или локальный статический) массив, не   принадлежащий классу.
-По сути хочу сделать так, чтобы массив APoints был одинаков для всех дочених классво (млин, наверное static напрашивается)
Как правильно-то сделать, вариантов ведь много, но наилучший должен быть один (на то он и наилучший  )
За что такая нелюбовь к глобальным массивам? Ну и в варианте 1 - массив и будет одинаков для всех объектов.
А про лучший вариант - не-а, он не будет один. Скорее всего для разных групп индивидов он будет свой (ну, у всех ведь свои предпочтения) и чем-то он будет лучшим. Да еще и для разных вариантов применения тоже возможно, что лучшими будут разные варианты реализации. Все это ИМХО, само собой Улыбаюсь
Вроде бы все. Пинать нЕ за что Улыбаюсь
Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
Джон
просто
Администратор

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

« Ответ #22 : 19-02-2006 17:40 » 

Сразу, вот за это пинать не будем:
Код:
CLine  *obj_line, line;
obj_line=&line;
obj_line->NewPoint(LOWORD(lParam),HIWORD(lParam));

         if(пользователь выбирает Безье)
         ((CBezye *)obj_line)->Approximate();
         else
         ((CLagranje*)obj_line)->Approximate();
- лучше сразу расстреляем из крупнокалиберного пулемёта, чтоб не мучился Улыбаюсь Я даже не знаю как это назвать? Анти-ООП пожалуй слишком мягко.

Про остальное - теперь всё понятно.
Это программа по сути легко решается без всякого ООП

ЛЮБАЯ ЗАДАЧА РЕШАЕТСЯ БЕЗ ВСЯКОГО ООП! разница только в "легко или нет" Ага

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

ООП с наследованием, а именно это, если я правильно понял, ты и хочешь попробовать на примере,  себя оправдает в случае, если нужно рисовать много разнотипных объектов "одновременно",  по той простой причине, что можно создавать списки (массивы) однотипной информации. Примитивный случай - у тебя есть объект типа Точка с Х и У координатами. Он знает как себя рисовать. Тогда ты создаёшь список list<CТочка> и счастлив.
А как быть, если в одном случае надо рисовать треугольник, в другом круг и тд и тп?
Тогда и приходит на помощь полиморфизм. С возможностью создать список одного типа - CFigure.

list<CFigure> lst;
// инициаллизация объектов public CFigure и вставка их в список
list<CFigure*>::iterator i = lst.begin();
while(i!=lst.end())
{
   (*i)->Draw(pDC);
   i++;
}
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"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."
Alf
Гость
« Ответ #23 : 19-02-2006 18:19 » 

Я понимаю, что вы (Джон, Альф) мне говорите, но мне кажется вы не все совсем поняли, что у меня к чему.

Поначалу - да, задача не слишком четко сформулирована. Ты только сейчас уточнил, что нужно делать на самом деле, и решение видится мне уже другим.

Я вот как думал сделать:
Запускается программа и создается объект родительского класса, т.е. CLine *obj=new CLine;
Потом пользователь на рабочей области окна щелкает мышкей тем самым назначая контрольные точки. Функция NewPoints() всего навсего заполняет массив тех самых контрольных точек. Т.е. пользователь щелкнул по области окна и координаты щелчка занеслись в массив. Пользователь поставит таких точек всего 3-4 (на желание).
После того, как пользователь поставил эти контрольные точки он решает с помощью какого алгоритма будет строится кривая, либо методом Безье, либо методом Лагранжа. Заострите здесь внимание пожалуйста. Сначала ставим точки и только потом решаем каким алгоритмом строить.

Вот оно, самое главное,  с чего нужно было начинать. Одна и та же линия может иметь несколько представлений: Безье, Лагранжа, возможно, также ты захочешь вывести ее в виде ломаной, потом добавить еще какие-то сплайны... При этом набор исходных точек не меняется.

Если делать как предлагаете вы (это конечно верно с точки зрения ООП), то пользователь сначала должен выбрать алгоритм построения кривой и только потом он будет ставить контрольные точки. Так ведь получается?

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

Если же делать как вы, но реализовывать то, что я запланировал, то здесь 2 варианта:
1) Создать глобальный массив этих контрольных точек. Когда пользователь будет ставить контрольные точки, то будет заполняться глобальный массив. Затем, когда пользователь выберет алгоритм, то как раз  тогда создастся объект нужного дочернего класса и в него уже надо будет передать этот массив контрольных точек.

Если хочешь овладеть хорошим стилем ООП, забудь о глобальных объектах. Тем более что болеепригодные для ООП языки - C# и Java - вообще не позволят тебе создать ничего глобального, там в самом языке нет нужных для этого средств. Глобальные объекты столь же чужды для ООП, сколь оператор GOTO для структурного программирования.

2)Сразу создать 2 объекта (по одному для каждого дочернего класса). Когда пользователь будет ставить контрольные точки, то для каждого объекта производить заполнение массива контрольных точек.

Я вижу более изящное решение. Изложу его чуть позже.

Теперь должно многое проясниться. Мне ведь как раз интересно унать как сделать так, чтобы все объекты дочерних классов располагали одним на всех массивом APoints. Понимаете? Это, думаю, можно было бы достичь, сделав массив APoints статическим (static). Я прав? Если да, то хорошо, но можно ли сделать по-другому?

Можно. См. выше.

Я пока вот как делаю:
Код:
...
         if(пользователь выбирает Безье)
         ((CBezye *)obj_line)->Approximate();
         else
         ((CLagranje*)obj_line)->Approximate();
...

Солидарен с Джоном - форменное безобразие. Бессмысленная и опасная конструкция.

Как правильно-то сделать, вариантов ведь много, но наилучший должен быть один (на то он и наилучший Ага )

Не должен. Каждый вариант обладает своими особенностями, и выбор зависит от того, как ты расставишь приоритеты. В одних случаях критично быстродействие (если тебе нужно построить миллион кривых, даже лишняя миллисекунда имеет значение). В других необходимо минимизировать память любой ценой (например, программа должна работать на карманном компьютере или сотовом телефоне). Лично я во главу угла ставлю ясность программы, удобство отладки и сопровождения и легкую расширяемость, если явно заказчиком не предъявляются другие требования. Свое видение решения изложу чуть позже.
Записан
Джон
просто
Администратор

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

« Ответ #24 : 19-02-2006 18:34 » 

зы Забыл, Михалыч, ты это... заходи, плюрализм мнений в вопросах обучения и объяснения особенно важен. ИМХО.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"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."
Alf
Гость
« Ответ #25 : 19-02-2006 19:31 » 

Вот мое предложение:


Вкратце суть:

1. Класс CLine - обычный, неабстрактный. Класс включает в себя набор точек, образующих ломаную.

2. Класс CLine включает экземпляр абстрактного класса CApproxymation.

3. Класс CApproxymation включает единственный абстрактный метод Approxymate.

4. Класс CApproxymation имеет двух (в данный момент) потомков - неабстрактные классы CApproxBezier и CApproxLagrange. Их назначение - задать соответствующую реализацию метода Approxymate.

5. Если понадобится добавить какой-то еще алгоритм аппроксимации (назовем его условно XSpline), в программе не придется менять абсолютно ничего. Нужно будет лишь дописать новый класс CApproxXSpline, сделать его производным от CApproxymation и реализовать метод Approxymate.

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

Работа с классом CLine:

1. Заполняем список точек.

2. Создаем нужный нам вариант класса-аппроксиматора внутри CLine.

3. Вызываем его метод Approxymate.

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

* Line2.gif (8.84 Кб - загружено 2019 раз.)
« Последнее редактирование: 19-02-2006 19:35 от Alf » Записан
Alf
Гость
« Ответ #26 : 19-02-2006 19:56 » 

Мне лично импонирует идея глобального массива точек, м.б. и статического, хотя и не обязательно.
...
За что такая нелюбовь к глобальным массивам?

А зачем тогда использовать объекты вообще? Вытащить все переменные наружу, свалить в одну большую глобальную кучу - и делай, что хочешь. Красота, никаких ограничений.

Может, конечно, это и излишне, но все же напомню, что инкапсуляция данных является одной из основных идей ООП. Доступ к данным ограничивается до необходимого минимума. Обычно менять их значения могут лишь члены класса, которому принадлежат данные. Зачем это нужно, вряд ли имеет смысл объяснять.
Записан
Alf
Гость
« Ответ #27 : 20-02-2006 08:36 » 

Вдогонку к вышесказанному.

Только что мне вернули книжку "Приемы объектно-ориентированного проектирования" Банды Четырех. Проверил, не подвела ли меня память. Предложенный мной вариант именуется у них паттерном "Strategy" и описан на странице 300. Если кто еще не обзавелся этой книгой (и очень много потерял), напоминаю, что она есть в нашей библиотеке: https://club.shelek.ru/download.php?id=327

Не советую пренебрегать ей, т.к. знание паттернов и умение их применять - одно из отличий профессионала от любителя. Еще о паттерне "стратегия" можно узнать здесь (фактически это глава из той самой книги без примеров кода): http://ooad.asf.ru/patterns/patterninfo.asp?ID=22
Записан
nikedeforest
Команда клуба

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

« Ответ #28 : 20-02-2006 09:25 » 

Alf,  в целом я понял замысел, но пока еще не реализовал. При реализации наверное новые вопросы
появятся. Попробую сегодня реализовать.
Записан

ещё один вопрос ...
Михалыч
Команда клуба

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

« Ответ #29 : 20-02-2006 13:42 » 

Мне лично импонирует идея глобального массива точек, м.б. и статического, хотя и не обязательно.
...
За что такая нелюбовь к глобальным массивам?

А зачем тогда использовать объекты вообще? Вытащить все переменные наружу, свалить в одну большую глобальную кучу - и делай, что хочешь. Красота, никаких ограничений.

Может, конечно, это и излишне, но все же напомню, что инкапсуляция данных является одной из основных идей ООП. Доступ к данным ограничивается до необходимого минимума. Обычно менять их значения могут лишь члены класса, которому принадлежат данные. Зачем это нужно, вряд ли имеет смысл объяснять.
Вай-вай! Сдается мне, что не все так запущено Улыбаюсь
Я как раз привык отделять данные от их обработки. Привычка - специфика работы с системами сбора и обработки данных. Если очень грубо - данные валятся в базу, а приложение выбирает из нее то, что ему надо и делает с ними то, что надо. Данных может быть много и весьма разнообразных. Пихать их иногда внутрь класса - увольте. Поэтому в данном случае я и рассматривал эту задачу как возможный вариант - данные могут ведь и не только от пользователя приходить. Массив - прототип некой базы данных, где хранится информация о точках. Не вижу криминала. На мой взгляд, ООП применять нужно. Но не фанатично Улыбаюсь А так, как удобнее. Оно ведь в конце концов призвано жизнь облегчать, а не усложнять. Более того, раз уж пошла "такая пьянка", буду "резать последний огурец" Улыбаюсь Думаю, не скажу ничего нового - ООП применять нужно не везде. Можно, но иногда не нужно. Но можно. Ведь одно из основных преимуществ, которое дает ООП - повторное использование кода. А если его повторно использовать негде? Тогда мне лично применять ООП просто  удобнее (хотя и не обязательно), привычнее, что-ли... Образ мышления уже изменен объектным подходом Улыбаюсь Однако мне приходится довольно много писать не очень больших программ, где нет "повторимости" кода. Вы скажете - так не бывает... Бывает Улыбаюсь Конечно, не все "неповторимо и повторно не применимо", но все же... Если проще и быстрее написать приложение с использованием глобального массива - да я и применю его, и не будет у меня голова болеть о том, что я нарушаю "святые каноны" ООП. Опять же оговорюсь - все зависит от задачи Улыбаюсь
...знание паттернов и умение их применять - одно из отличий профессионала от любителя. Еще о паттерне "стратегия" можно узнать здесь (фактически это глава из той самой книги без примеров кода): http://ooad.asf.ru/patterns/patterninfo.asp?ID=22
Как-то давно, и не помню в какой теме, но абсолютно точно, я уже говорил - что мне, например, паттерны интересны теоритически, но не нужны практически. И STL тоже далеко не всегда нужна. Ну и что? Не профессионально? Зачастую (в системах управления например) - чем проще тем лучше - к вопросу о надежности, отлаживаемости, читабельности и т.п.
А вообще - была такая тема - Олегатор ее поднимал - границы применения ООП. Это уже наверное туда Улыбаюсь
Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
Alf
Гость
« Ответ #30 : 20-02-2006 14:34 » 

Ведь одно из основных преимуществ, которое дает ООП - повторное использование кода.

Я бы не сказал, что оно основное. Немаловажное - да, особенно когда речь идет о промышленном производстве софта. Однако хорошую процедуру ничто не мешает также применить повторно. В конце концов, библиотеки стандартных функций появились задолго до ООП, а уж они-то отнюдь не для одноразового применения делались. Ставить знак тождества между объектным подходом и повторным искпользованием кода не совсем правильно. Любой качественный код годится для повторного использования, независимо от объектности.

У ООП есть ряд куда более весомых достоинств, которые делают его предпочтительным даже для разовых разработок.

Если проще и быстрее написать приложение с использованием глобального массива - да я и применю его, и не будет у меня голова болеть о том, что я нарушаю "святые каноны" ООП. Опять же оговорюсь - все зависит от задачи Улыбаюсь

Скорее - от удачи. Если речь о простой учебной задаче, как в данном случае, такой подход с натяжкой пригоден (с натяжкой потому, что лучше всегда делать правильно, а не выборочно; если в гостях вести себя чинно, а дома сморкаться в скатерть, потому что так удобнее, рано или поздно эта привычка подведет хозяина). Чем больше тысяч строк в проекте, тем больше вероятность путаницы.

Как-то давно, и не помню в какой теме, но абсолютно точно, я уже говорил - что мне, например, паттерны интересны теоритически, но не нужны практически. И STL тоже далеко не всегда нужна. Ну и что? Не профессионально?

Не вижу связи. STL мне вообще практически не нужна, поскольку от использования C++ в новых проектах я отказался полностью. Паттерны - это результат фундаментальной работы четырех не самых глупых людей, перелопативших горы проектов и выделивших наиболее общие и удачные решения. Как их можно сравнивать с частной библиотекой одного из языков программирования, пусть некогда и популярного?

Зачастую (в системах управления например) - чем проще тем лучше - к вопросу о надежности, отлаживаемости, читабельности и т.п.

Применение паттернов вовсе не означает автоматическое ухудшение надежности, отлаживаемости, ситабельности и т.п. Не говоря уже о простоте. Использование тщательно продуманного решения вовсе не обязательно проигрывает самостоятельно изобретенному велосипеду, как бы высоко изобретатель не ценил свое детище. Чем больше готовых наработок используешь, тем больше времени на обдумывание нестандартной части задачи остается.

А вообще - была такая тема - Олегатор ее поднимал - границы применения ООП. Это уже наверное туда Улыбаюсь

Не знаю, не знаю... Человек задал вопрос о работе с классами, следовательно, он уже сделал выбор в сторону ООП, так что границы проводить поздно, мы уже на территории ООП. Конечно, можно фактически писать на FORTRAN'e, используя синтаксис C++. Но нужно ли?

А вообще критерий истины - практика. Предложенный мной шаблонный вариант представляется мне простым изящным, надежным, легким в реализации и легко пригодным для расширения, ежели такая потребность возникнет.  Приведи решение с глобальными объектами, которое не уступит предложенному по совокупности этих параметров, в особенности в части строгой типизации, и я охотно признаю поражение ООП.
« Последнее редактирование: 20-12-2007 16:11 от Алексей1153++ » Записан
Михалыч
Команда клуба

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

« Ответ #31 : 20-02-2006 17:15 » 

Alf, ну зачем же так-то? Улыбаюсь От легких передергиваний до неприятных аналогий Отлично
Повторюсь - "одно из основных преимуществ". Я ведь тоже не сказал, что оно основное. И именно ООП я уже много лет успешно использую в "разовых" разработках. По поводу задачи (а не удачи) останусь при своем мнении. Об неудачных на мой взгляд аналогиях скромно умолчу Улыбаюсь
Ну, паттерны и STL я нигде и ниразу не уравнивал. Просто прозвучало (может мне так показалось) мнение, что без применения STL и паттернов проектирования в профессиональном программировании уже и делать нечего - любительский уровень. Я лишь хотел сказать, что это не так Улыбаюсь
Предложенное тобой решение и просто и изящно и надежно. Кто бы спорил Улыбаюсь Однако, хранить данные так, как ты предлагаешь - мне не как-то некомфортно, что-ли... Личные предпочтения Улыбаюсь  Приводить решение ради "поражения ООП" конечно же бессмысленно, поскольку я и не оспариваю его преимуществ. Всего лишь говорю о том, что применять его можно по-разному Улыбаюсь
Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
Alf
Гость
« Ответ #32 : 20-02-2006 17:52 » 

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

Если и звучало, то точно не от меня. Я убежден, что даже досконального знания какого-либо языка и пары-тройки библиотек совершенно недостаточно для профессионала. Перечень библиотечных функций всегда можно
посмотреть в справочнике.

Отличает профессионала как раз умение разработать каркас нетривиального проекта, его архитектуру. Набивать его функциями можно поручить и новичку, при должном усердии справится. STL к архитектуре не имеет никакого отношения, паттерны - самое непосредственное. Поэтому знание паттернов столь же необходимо профессионалу, сколь владение основными алгоритмами, основами логики, теории конечных автоматов и т.п. (не буду повторяться, эту тему неоднократно поднимали уже).

Однако, хранить данные так, как ты предлагаешь - мне не как-то некомфортно, что-ли... Личные предпочтения Улыбаюсь

Весь юмор в том, что данные-то я еще никак не предлагал хранить, я предложил лишь общую структуру объектов. Пускай себе класс "линия" содержит в себе указатель на массив точек. Отношение агрегирования вовсе не означает, что все данные нужно физически вколотить в класс-контейнер. Кстати, на C# или Java это и не получится при всем желании. Хотя массив, конечно, далеко не лучший выбор с точки зрения динамического удаления/добавления точек, но как вариант рассмотреть можно.

Статический массив, да еще и глобальный, - это все же не вариант. Заранее не зная, сколько точек в линии, какого размера ты его объявишь? Миллион, чтобы хватило на все случаи жизни? А если не хватит? А если нужны тысячи линий по 4 точки в каждой? Нормальный на мой взгляд подход - это когда данные передаются классу после его создания, а сколько их будет - задача внешнего по отношению к классу приложения.

Приводить решение ради "поражения ООП" конечно же бессмысленно, поскольку я и не оспариваю его преимуществ. Всего лишь говорю о том, что применять его можно по-разному Улыбаюсь

Но не настолько же по-разному, чтобы от идеи ООП ничего не осталось, а на "объектность" программы нам намекало лишь слово "class" в тексте программы. Тем более что принципиальных отличий класса от структуры в C++ нет. Можно взять любую программу на C 20-летней давности, переименовать структуры в классы - и все, хотели объекты - получите. Объектности в такой программе не больше, чем структурности в программе, где каждый второй оператор GOTO.
Записан
Михалыч
Команда клуба

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

« Ответ #33 : 21-02-2006 14:57 » 

Alf, я стараюсь быть по возможности точным в своих словах Улыбаюсь Это же твои?
Цитата
...знание паттернов и умение их применять - одно из отличий профессионала от любителя.
И я полностью с тобой согласен - "одно из". Не более того. Несколько лет назад, когда о паттернах еще никто и слыхом не слыхивал профессионалы были. Другое дело сейчас - паттерны вошли в "обиход" и без них уже кое-где совсем никак. Но в очень многих случаях и сейчас вполне без них обходятся при создании программ отнюдь не любительского уровня (и через несколько лет возможно будут обходится, а там глядишь еще чего нового придумают Улыбаюсь - появятся новые профессионалы - это жизнь...). Поэтому я считаю, что знание паттернов желательно, но не жизненно необходимо профессионалу, а вот владение основными алгоритмами, логикой, теорией автоматов
необходимо бесспорно...
Цитата
Весь юмор в том, что данные-то я еще никак не предлагал хранить, я предложил лишь общую структуру объектов.
Глядя на все уже написанное теперь понимаю, что скорее по своему невниманию понял мысль не до конца. Меня смутило вот это:
Цитата
Класс CLine - обычный, неабстрактный. Класс включает в себя набор точек, образующих ломаную.
А поскольку, ради экономии траффика, картинки у меня не грузятся без острой необходимости, то диаграммы классов я не увидел Улыбаюсь Ну и понял буквально Отлично
Статический массив - ясное дело не вариант. Я скорее всего просто ошибся, поскольку - вот оно - процитирую сам себя:
Цитата
Мне лично импонирует идея глобального массива точек, м.б. и статического, хотя и не обязательно. И указатель на массив в любом дочернем классе. Во всяком случае я не стал бы заводить сразу 2 объекта дочерних классов и заполнять каждому из них свой массив. Ладно бы еще когда их только 2...3...10. А если их фиг знает сколько - читай очень много? А еще лучше вообще неизвестно сколько. Создавать динамически по мере надобности - мне так кажется
Смешно - ведь в этом случае мы говорим об одном и том же Улыбаюсь
Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
Olegator
Команда клуба

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

« Ответ #34 : 21-02-2006 21:54 » 

Еще о паттерне "стратегия" можно узнать здесь (фактически это глава из той самой книги без примеров кода): http://ooad.asf.ru/patterns/patterninfo.asp?ID=22
Это как понимать:
Цитата
клиенты должны «знать» о различных стратегиях. Потенциальный недостаток этого паттерна в том, что для выбора подходящей стратегии клиент должен понимать, чем отличаются разные стратегии. Поэтому наверняка придется раскрыть клиенту некоторые особенности реализации. Отсюда следует, что паттерн стратегия стоит применять лишь тогда, когда различия в поведении имеют значение для клиента;
Возможное нарушение инкапсуляции? А клиент это один из видов паттерна?
Записан
Alf
Гость
« Ответ #35 : 21-02-2006 23:20 » 

Цитата: Михалыч link=topic=8222.msg121046#msg121046 daА зачем мнеte=1140533845
Alf, я стараюсь быть по возможности точным в своих словах Улыбаюсь Это же твои?
Цитата
...знание паттернов и умение их применять - одно из отличий профессионала от любителя.
И я полностью с тобой согласен - "одно из". Не более того.

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

Цитата: Михалыч link=topic=8222.msg121046#msg121046 daА зачем мнеte=1140533845
Несколько лет назад, когда о паттернах еще никто и слыхом не слыхивал профессионалы были.

Михалыч, ты не забывай, что для информатики несколько лет - громадный срок, каждый год стоит десятилетия в какой-либо иной области. Вот представь себе ситуацию: ты летаешь на каком-нибудь фанерном "фокке-вульфе" времен первой мировой войны, стреляешь в противника из револьвера, бросаешь тюки горящей пакли... В общем, для своего времени экипировка - супер. И летаешь лучше всех - ас, легенда. Потом засыпаешь почти на столетие, а проснувшись, первым делом бежишь на аэродром и забираешься в "МиГ" последней модели. Далеко ты на нем улетишь при всех былых заслугах?

Если прекращаешь идти в ногу со временем, очень быстро к слову  "профессионал" добавляется "бывший". Увы, такова жизнь.

Цитата: Михалыч link=topic=8222.msg121046#msg121046 daА зачем мнеte=1140533845
Другое дело сейчас - паттерны вошли в "обиход" и без них уже кое-где совсем никак. Но в очень многих случаях и сейчас вполне без них обходятся при создании программ отнюдь не любительского уровня (и через несколько лет возможно будут обходится, а там глядишь еще чего нового придумают Улыбаюсь - появятся новые профессионалы - это жизнь...). Поэтому я считаю, что знание паттернов желательно, но не жизненно необходимо профессионалу, а вот владение основными алгоритмами, логикой, теорией автоматов
необходимо бесспорно...

А кое-где обходятся FORTRAN-IV, а кое-где счетами и логарифмической линейкой... Я своими глазами видел сложнейшую навигационную систему, которая до сих пор работает на IBM-370 (!!!), потому что заменить нечем, а поддерживать такого монстра в рабочем состоянии, когда запчасти нужно искать не на складе, а в музее, настоящее мучение. И в машинных кодах можно писать, и наверняка можно найти пару-тройку примеров, когда это оправданно. Речь в данный момент идет о разработке типовых программ для типового оборудования, а не каких-то спецвычислителей в реальном времени.

Я бы сравнил паттерны с типовыми шахматными комбинациями. Сначала кто-то из взрослых показывает тебе, как ходят фигуры. Потом ты играешь с друзьями и, возможно, обыгрываешь их за счет сообразительности. А потом в один непрекрасный момент напротив тебя оказывается шахматист-разрядник и уделывает тебя под орех. При этом он отнюдь не умнее тебя. Просто ты двигаешь фигурки, а он играет сицилианскую защиту. Ты напрягаешь умище, продумывая каждый ход, а он знает, что такой ответ приведет его к проигрышу, а такой даст выигрыш пешки через три хода. Конечно, если ты гений, у тебя есть небольшой шанс выиграть без знания теории. Хотя, если на часах выставлено по 10 минут на партию, ты просто не успеешь со своими выкладками.

Вообще там, где начинается систематизация, шаманство превращается в науку. Паттерны - это тоже систематизация. Мне весьма странно было бы увидеть гроссмейстера, который в ответ на предложение играть защиту Филидора спросит: "А чаво это???". Ничуть не лучше выглядит программист-профи, который в ответ на предложение использовать паттерн "декоратор" недоуменно таращит глаза. Причем, заметь, знание защиты Филидора вовсе не означает, что наш шахматист будет пихать ее куда надо и не надо. Это значит лишь, что когда придется, он сможет применить свои знания, не изобретая велосипед. Точно так же знание паттернов дает тебе: 1) возможность применить их там, где это уместно; 2) возможность избежать их бездумного применения там, где это неуместно. Незнание дает тебе лишь вторую возможность, так что решай сам.

Записан
Alf
Гость
« Ответ #36 : 21-02-2006 23:36 » 

Возможное нарушение инкапсуляции?

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

Как видишь, с точностью до наоборот. Нарушение инкапсуляции - это очень серьезное ухудшение качества программы, а паттерны предназначены для его улучшения.

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

А клиент это один из видов паттерна?

Нет, клиент - это класс, который использует данный класс (то есть находится за пределами нашего обсуждения). В нашем случае клиент - это класс, который создает линию, готовит данные о координатах точек и выбирает способ интерполяции.
Записан
Михалыч
Команда клуба

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

« Ответ #37 : 23-02-2006 06:33 » 

Ну, ладно... Спор становится беспредметным. Ососбенно по поводу необходимого и достаточного. Для меня - потому, что я именно не вижу уместности паттернов в своих проблемах, а может я просто не настолько их знаю (как там было про кошек? - "...ты просто не умеешь их готовить..." Улыбаюсь )
Полечу дальше на деревянно-парусиновом "Фармане" Отлично
Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
nikedeforest
Команда клуба

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

« Ответ #38 : 25-02-2006 00:56 » 

Один вопрос не дает мне покоя. Зачем нужен класс CPoint?
Я так понимаю, что из-за безопасности, но неужели нельзя защитить массив точек в классе СLine?
Записан

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

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

« Ответ #39 : 25-02-2006 01:21 » 

А что есть точка? Улыбаюсь Такого типа данных нет. Таким образом "массив точек" не определён. Т.е. или делать структуру или объект (класс), который инкапсулировал бы данные например int X; и int Y;
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"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."
nikedeforest
Команда клуба

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

« Ответ #40 : 25-02-2006 01:35 » 

Ну я делал так:
Код:
int Arr_Point[2][100];
ArrPoint[0]--x
ArrPoint[1]--y
ArrPoint[][0] - значение координаты
Т.е. создава двумерный массив.
Но мне кажется что вам (тебе, Альфу) этот способ не понравится. Мне бы хотелось знать воше мнение.
И кстати, Альфу почему-то не понравилось, что я использовал структуру.
Записан

ещё один вопрос ...
Михалыч
Команда клуба

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

« Ответ #41 : 25-02-2006 04:25 » 

Нет, класс CPoint только из соображений безопасности - это неправильно, конечно.
Цитата
А что есть точка?  Такого типа данных нет. Таким образом "массив точек" не определён. Т.е. или делать структуру или объект (класс), который инкапсулировал бы данные например int X; и int Y;
Правильно Джон говорит. В первую очередь для этого - создать тип и инкапсулировать данные.
И почему Альфу не понравилась структура - он уже писал, посмотри еще раз внимательнее:
Цитата
...Дело в том, что в структуре все члены открыты, поэтому нет никакой гарантии...
...точку тоже лучше сделать классом, а не массивом из двух чисел...
Если сделать класс, описывающий точку, все сразу станет даже выглядеть проще.
Примерно так:
Код:
class POINT
{
  public:
    POINT(): X(0), Y(0); //конструктор по умолчанию
    POINT(int a, int b): X(a), Y(b);  //еще конструктор
    POINT(const POINT& P) { X=P.getX(); Y=P.getY(); } //конструктор копирования
    void setX(int C);
    void setY(int C);
    int getX(void);
    int getY(void);
  private:
    int X; //координаты точки
    int Y;
};
 
Потом заводим динамический массив (вовсе не обязательно vector<>, и вовсе не обязательно глобальный Улыбаюсь ), куда складируем, например, указатели на новые точки:
Код:
vector<POINT *> VP;
POINT *tp;
tp=new POINT(12, 13);
VP.push_back(tp);
А уже указатель на этот динамический массив удобно поместить (как один из вариантов) в класс CLine, в защищенном или нет, виде Улыбаюсь
« Последнее редактирование: 25-02-2006 04:27 от Михалыч » Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
nikedeforest
Команда клуба

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

« Ответ #42 : 26-02-2006 08:12 » 

Понятно теперь стало, спасибо. Никак не привыкну к инкапсуляции, т.е. к тому, что не надо образаться к переменной на прямую, а надо через метод.
Записан

ещё один вопрос ...
Страниц: 1 2 [Все]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines