IPB
ЛогинПароль:

> Внимание!

1. Пользуйтесь тегами кода. - [code] ... [/code]
2. Точно указывайте язык, название и версию компилятора (интерпретатора).
3. Название темы должно быть информативным.
В описании темы указываем язык!!!

Наладить общение поможет, если вы подпишитесь по почте на новые темы в этом форуме.

 
 Ответить  Открыть новую тему 
> Классы, наследственность
сообщение
Сообщение #1


Бывалый
***

Группа: Пользователи
Сообщений: 212
Пол: Мужской

Репутация: -  0  +


Есть вот такая программа.

#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
#include <dos.h>
#include <graphics.h>
#include <string.h>
#include <math.h>
void move(int i);
// è½áßß öêâôÉÇ
class Figure
{
protected:
int Color;
int CenterX;
int CenterY;
public:
Figure(int iCenterX, int iCenterY)
{
Color = RED;
CenterX = iCenterX;
CenterY = iCenterY;
}
void SetNewColor(int NewColor)
{
Hide();
Color=NewColor;
Show();
}
virtual void Show() = 0;
virtual void Hide()
{
int prev_col = Color;
Color=getbkcolor();
Show();
Color = prev_col;
}
void Move(int DeltaX, int DeltaY)
{
Hide();
CenterX+=DeltaX;
CenterY+=DeltaY;
Show();
}
virtual ~Figure() {};
};

class Butterfly: public Figure
{
private:
int Radius;
int RadiusX;
int RadiusY;
int Stangle;
int Endangle;
public:
Butterfly(int iCenterX, int iCenterY, int iStangle,int iEndangle,int iRadiusX,int iRadiusY,int iRadius) :
Figure(iCenterX, iCenterY)
{
Stangle=iStangle;
Endangle=iEndangle;
Radius=iRadius;
RadiusX = iRadiusX;
RadiusY = iRadiusY;
}
void Show();
};

class Hexe: public Figure
{
private:
int RRadius;
int rRadius;
public:
Hexe(int iCenterX, int iCenterY, int iRadius) :
Figure(iCenterX, iCenterY)
{
RRadius = iRadius;
rRadius = (sqrt(3)/2)*RRadius;
}
void Show();
};

class Combo:public Hexe,public Butterfly
{
public:
Combo(int iCenterX, int iCenterY, int iStangle,int iEndangle,int iRadiusX,int iRadiusY,int iRadius) :
Hexe( iCenterX, iCenterY, iRadius),Butterfly(iCenterX, iCenterY, iStangle,iEndangle, iRadiusX, iRadiusY,iRadius)
{}
void Show();
void Hide();
void Move(int x);
void SetNewColor(int colr);
~Combo(){};
};

void Hexe::Show()
{
int prev_color=getcolor();
setcolor(Color);
line(CenterX, CenterY+RRadius,CenterX-rRadius,CenterY+RRadius/2);
line(CenterX-rRadius,CenterY+RRadius/2,CenterX-rRadius,CenterY-RRadius/2);
line(CenterX-rRadius,CenterY-RRadius/2,CenterX,CenterY-RRadius);
line(CenterX,CenterY-RRadius,CenterX+rRadius,CenterY-RRadius/2);
line(CenterX+rRadius,CenterY-RRadius/2,CenterX+rRadius,CenterY+RRadius/2);
line(CenterX+rRadius,CenterY+RRadius/2,CenterX, CenterY+RRadius);
setcolor(prev_color);
}

void Butterfly::Show()
{
int prev_color=getcolor();
setcolor(Color);
circle(CenterX, CenterY-RadiusY, Radius/5);
ellipse(CenterX, CenterY+Radius/5, Stangle,Endangle,RadiusX,RadiusY);
line(CenterX-(sqrt(3)/2*Radius),CenterY-Radius/2,CenterX-20,CenterY);
line(CenterX-20,CenterY,CenterX-(sqrt(3)/2*Radius),CenterY+Radius/2);
line(CenterX-(sqrt(3)/2*Radius),CenterY-Radius/2,CenterX-(sqrt(3)/2*Radius),CenterY+Radius/2);
line(CenterX+(sqrt(3)/2*Radius),CenterY-Radius/2,CenterX+20,CenterY);
line(CenterX+20,CenterY,CenterX+(sqrt(3)/2*Radius),CenterY+Radius/2);
line(CenterX+(sqrt(3)/2*Radius),CenterY-Radius/2,CenterX+(sqrt(3)/2*Radius),CenterY+Radius/2);
setcolor(prev_color);
}

void Combo::Show()
{
Butterfly::Show();
Hexe::Show();
}

void Combo::Hide()
{
Butterfly::Hide();
Hexe::Hide();
}

void Combo::Move(int x)
{
Butterfly::Move(15*x,15*x);
Hexe::Move(15*x,15*x);
}

void Combo::SetNewColor(int colr)
{
Butterfly::SetNewColor(colr);
Hexe::SetNewColor(colr);
}

int main()
{ int n_menu;
while (1)
{
clrscr;
cout<<"1-Butterfly\n2-Hexe\n3-Combo\n4-Exit\n";
cin>>n_menu;
int gdriver = DETECT, gmode, errorcode;
initgraph(&gdriver, &gmode,
"../BGI");
errorcode = graphresult();
if (errorcode != grOk)
{
cerr<<"Graphics error";
cerr<<grapherrormsg(errorcode);
exit(1);
}
Butterfly F1(100,100,0,360,20,75,100);
Hexe F2(100,100,100);
Combo F3(100,100,0,360,20,75,100);
switch(n_menu)
{
case 1: cleardevice();F1.Show();break;
case 2: cleardevice();F2.Show();break;
case 3: cleardevice();F3.Show();break;
case 4: cout<<"Bay! Bay!\n";delay(750);return 0;
}
getch();
int maxcolor = getmaxcolor();
int direction = 1;
for (int color = 0; !kbhit(); color++)
{
if (color>maxcolor)
{color=0; direction*=-1;}

switch (n_menu)
{
case 1: F1.SetNewColor(color);F1.Move(10*direction,10*direction);break;
case 2: F2.SetNewColor(color);F2.Move(10*direction,10*direction);break;
case 3: F3.SetNewColor(color);F3.Move(direction);break;
}
delay(50);
}
closegraph();
}
}


По меню по очереди можно вывести бабочку, потом шестиугольник правильный, потом комбинированно бабочку в шестиугольнике. Бабочки и шестиугольник наследники от общего класса фигуры, а вот комбо от бабочки и шестиугольника. Не пойму вот следующее по идее класс Combo должен ведь унаследовать методы Move и SetNewColor, так как он наследник от Butterfly и Hex, которые в свою очередь наследуют данный метод от Figure. Но если выкинуть эти методы как сделано в выше представленном коде и напрямую обращаться например F3.SetNewColor(color);F3.Move(10*direction,10*direction); естественно компилятор материться. Так как правильно оформить наследственность и добраться до данных методов, не прописывая их в классе Combo и естественно не описывая так
void Combo::Move(int x)
{
Butterfly::Move(15*x,15*x);
Hexe::Move(15*x,15*x);
}

void Combo::SetNewColor(int colr)
{
Butterfly::SetNewColor(colr);
Hexe::SetNewColor(colr);
}


P.S. Как в спойлер код скрывать, а то как то не красиво длинный пост получается?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


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

А то на данный момент вообще не понятно, что же тебе в приведенном коде не нравится...

Цитата
Как в спойлер код скрывать
Сделать [ hide="Заголовок спойлера" ]Текст спойлера[ /hide ]
Только теги - без пробелов...

Сообщение отредактировано: IUnknown -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3


Бывалый
***

Группа: Пользователи
Сообщений: 212
Пол: Мужской

Репутация: -  0  +


IUnknown, описание класса Combo

class Combo:public Hexe,public Butterfly
{
public:
Combo(int iCenterX, int iCenterY, int iStangle,int iEndangle,int iRadiusX,int iRadiusY,int iRadius) :
Hexe( iCenterX, iCenterY, iRadius),Butterfly(iCenterX, iCenterY, iStangle,iEndangle, iRadiusX, iRadiusY,iRadius)
{}
void Show();
void Hide();
void Move(int x);
void SetNewColor(int colr);
~Combo(){};
};


сами методы
void Combo::Show()
{
Butterfly::Show();
Hexe::Show();
}

void Combo::Hide()
{
Butterfly::Hide();
Hexe::Hide();
}

void Combo::Move(int x)
{
Butterfly::Move(15*x,15*x);
Hexe::Move(15*x,15*x);
}

void Combo::SetNewColor(int colr)
{
Butterfly::SetNewColor(colr);
Hexe::SetNewColor(colr);
}

преподаватель говорит зачем создавать методы void Hide(); void Move(int x); void SetNewColor(int colr); у данного класса, ведь они наследуются. Вот мне интересно как их использовать без создания а по наследству, ведь если их убрать из описания класса, а потом попробовать обратиться напрямую, как обращаешься например F1.Move или F2.Move (F1 -Butterfly, F2- Hex), вот так F3.Move тогда компилятор ругается.
Я так понимаю потому что данный класс не прямой потомок от класса Figure ?

Сообщение отредактировано: Account -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Цитата
преподаватель говорит зачем создавать методы void Hide(); void Move(int x); void SetNewColor(int colr); у данного класса, ведь они наследуются. Вот мне интересно как их использовать без создания а по наследству
Преподаватель в своем уме? При множественном наследовании методов (да еще и виртуальных) с одинаковыми именами и с одной областью видимости (они все описываются в public-разделе, и наследование всегда общее, то есть все они видимы в потомках) возникает неоднозначность, которую компилятор не имеет права разрешать. Скажем:

#include <iostream>

class A
{
public:
virtual void f()
{
std::cout << "A::f()" << std::endl;
}
};

class B
{
public:
virtual void f()
{
std::cout << "A::f()" << std::endl;
}
};

class C : public A, public B
{
public:
C() : A(), B() { }
};

int main()
{
C obj;
obj.f(); // Какую из функций надо вызывать? Может одну, может обе. Тогда в каком порядке?
return 0;
}

Так что даже не выдумывай, без переопределения в классе Combo этой "прослойки" не обойдешься. Кстати, Липпман именно такой способ называет хорошим тоном программирования.

Но у тебя есть еще одна загвоздка.

Еще раз смотри: (Показать/Скрыть)


Оно тебе надо, чтоб базовый класс инициализировался 2 раза? Не надо.

Решение: (Показать/Скрыть)
Чувствуешь разницу?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #5


Бывалый
***

Группа: Пользователи
Сообщений: 212
Пол: Мужской

Репутация: -  0  +


Цитата(IUnknown @ 4.07.2011 20:33) *

Преподаватель в своем уме?
.....
Чувствуешь разницу?

Может и не в своем, уже старенький.

По поводу разницы, почувствовал, спасибо, как всегда доходчиво.
Вот бы у нас так преподавали.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Я.
****

Группа: Пользователи
Сообщений: 809
Пол: Мужской
Реальное имя: Саша

Репутация: -  11  +


т.е. на всякий случай лучше всегда делать виртуальное наследование?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Цитата
т.е. на всякий случай лучше всегда делать виртуальное наследование?
На всякий случай надо знать об этом подводном камешке. И поступать так, как тебе нужно для решения задачи. Иногда (правда редко) нужно, чтобы при множественном наследовании базовый класс инициализировался при инициализации каждого потомка, иногда (чаще всего) не нужно. Поэтому, если ты будешь знать эту особенность - сможешь делать так, как нужно в твоем случае...
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


Бывалый
***

Группа: Пользователи
Сообщений: 212
Пол: Мужской

Репутация: -  0  +


Кстати, столкнулся еще с проблемой такой, что остаются следы после передвижения и именно от линий. Вот когда баловался выводил окружность, эллипс и двигал все нормально, как только появляются линии. при движении остаются следы, будто не стирается. Вот на примере выше, бабочка еще нормально, но шестиугольник и комбинированная фигура. при движении оставляет следы. В чем проблема и как от нее избавиться?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Вот кстати, без виртуального наследования следы однозначно будут оставаться при движении объекта типа Combo. Причем не только от линий, а и от эллипсов, то есть, объект будет просто напросто некорректно перерисовываться. Именно потому, что не надо второй раз инициализировать Figure... Рисоваться и стираться будут разные объекты. Как только ты сделаешь наследование виртуальным - этот глюк пропадет, объект Figure останется только один...

А насчет как избавиться от следов линий - не знаю, Wine запускать лениво, да и компилятор TurboC я уже стер... Теоретически - если ты уверен, что это линии "недоудаляются" - попробуй при стирании ставить бОльшую толщину линии (не NORM_WIDTH, который 1, как обычно, а THICK_WIDTH, который = 3). То есть, перед удалением установи через setlinestyle толстую линию, а потом, перед отрисовкой - опять обычную, узкую...
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10


Бывалый
***

Группа: Пользователи
Сообщений: 212
Пол: Мужской

Репутация: -  0  +


IUnknown, добавил виртуальное наследование к бабочке и шестиугольнику, но компилятор ругается в конструкторе Combo на то что не найден конструктор для инициализации базового класса Figure (с английским у меня плохо, но что то в этом роде)
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #11


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Цитата
но компилятор ругается в конструкторе Combo на то что не найден конструктор для инициализации базового класса Figure
smile.gif Я знал, что так и будет... Вас что, не учили виртуальному наследованию?

Сначала - как это происходит при наследовании обычном:
class base {
// ...
};

class A : public base {
// ... тут инициализируется базовый класс
};
class B : public base {
// ... и тут инициализируется базовый класс
};

class C : public A, public B {
// Здесь достаточно инициализировать прямых предков, но не ИХ предков
C() : A(), B() {}
// ...
};

, то есть, тебе было достаточно в списке инициализации написать только инициализацию тех классов, от которых ты наследовался, а уже они сами будут вызывать конструктор СВОИХ предков... Более того, тебе было запрещено писать в списке инициализации C() конструктор base, потому что ты от него напрямую не наследовался...

В случае с виртуальным базовым классом такой вариант не проходит. Класс C должен содержать одну копию base, поэтому надо инициализировать виртуальный базовый класс в наиболее удаленном от него потомке (чтоб потом не спрашивать себя, а откуда же был инициализирован базовый класс, из A или из B?). У тебя наиболее удаленный - не Hexe и не Butterfly, а Combo. Компилятор при виртуальном наследовании ждет инициализации не только Hexe + Butterfly, но и инициализации Figure. Если ты не записываешь его конструктор в список инициализации - будет вызван дефолтный конструктор (без параметров). У тебя и его нет, компилятор старый, не создает конструкторов самостоятельно. Надо добавить инициализацию ручками (все равно ты и в Hehe и в Butterfly одинаково вызываешь конструктор Figure):

class Combo : public Hexe, public Butterfly
{
public:
Combo(int iCenterX, int iCenterY, int iStangle, int iEndangle, int iRadiusX, int iRadiusY, int iRadius) :
Hexe(iCenterX, iCenterY, iRadius),
Butterfly(iCenterX, iCenterY, iStangle, iEndangle, iRadiusX, iRadiusY, iRadius),
Figure(iCenterX, iCenterY)
{}
// ...

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

Сообщение отредактировано: IUnknown -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #12


Бывалый
***

Группа: Пользователи
Сообщений: 212
Пол: Мужской

Репутация: -  0  +


Очередной раз спасибо за разъяснение. Учусь на заочном отделении, а там преподаватели не учат, а в лучшем случае если повезет могут дать консультацию.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 23.12.2024 19:49
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name