
Лекция 8
Конструкторы при наследовании классов
В языке С++ как базовый, так и производный классы могут иметь конструкторы. Конструктор базового класса создает часть объекта, соответствующую базовому классу, а конструктор производного класса _ часть объекта, соответствующую производному классу.
Если конструктор определен только в производном классе, то он создает объект производного класса. Часть объекта, соответствующую базовому классу, создает конструктор по умолчанию.
Рассмотрим пример использования конструктора только в производном классе.
Включим в класс TR предыдущего примера конструктор.
class TR:public GEOM
{public:
char type_tr[80];//тип треугольника
TR(char *st, double a,double b)//конструктор
{setw(a);
seth(b);
strcpy(type_tr,st);
}
double area()
{return getw()*geth()/2;}
void showtype()
{cout<<type_tr<<’\n’;}
};
Главная функция в этом примере может выглядеть так:
void main()
{ TR t(“равнобедренный”,4.0.4.0);;
cout<<”Информация о треугольнике:\n”;
t.showtype();//метод производного класса
t.show();//метод базового класса
cout<<”Площадь=”<<t.area()<<’\n’;
}
Если конструкторы имеются и в базовом и в производном классах, то производный класс должен явно вызывать конструктор базового класса для инициализации той части объекта, которая соответствует базовому классу.
Определение конструктора производного класса выглядит так:
<имя производного класса>(<список параметров>):<имя базового класса>(<список значений>)
{<тело конструктора производного класса>}
Предположим, что в базовом классе GEOM есть конструктор:
GEOM(double a, double b)
{w=a;
h=b;
}
Тогда конструктор производного класса TR выглядит так:
TR(char *st, double a, double b):
GEOM(a,b)
{strcpy(type_tr,st);}
Здесь конструктор TR вызывает конструктор GEOM с параметрами a и b, который инициализирует поля w и h , а затем инициализирует свое поле type_tr.
Рассмотрим пример.
Построить иерархию классов “точка-окружность” на языке С++. Пусть базовый класс point включает координаты точки , конструктор, функцию рисования точки на экране и функцию гашения точки. Пусть производный класс circ содержит радиус окружности, конструктор, функцию рисования окружности и функцию гашения окружности.
#include<conio.h>
#include<graphics.h>
class point
{protected:
int x,y;
public:
point(int xi,int yi)
{x=xi;y=yi;}
void show()
{putpixel(x,y,getcolor());}
void hide()
{putpixel(x,y,getbkcolor());}
};
class circ: public point
{protected:
int radius;
public:
circ(int xi,int yi,int ri):point(xi,yi)
{radius=ri;}
void show()
{circle(x,y,radius);}
void hide()
{int bk=getbkcolor();
int cc=getcolor();
setcolor(bk);
circle(x,y,radius);
setcolor(cc);
}
};
void main()
{int dr=DETECT;int dm;
initgraph(&dr,&dm,"c:\\BORLANDC\\BGI");
circ a(200,50,20);
circ d(500,200,30);
a.show();
getch();
d.show();
getch();
closegraph();
}
Множественное наследование
В языке С++ допускается множественное наследование- возможность создавать производные классы на основе нескольких базовых классов.
В этом случае производный класс определяется следующим образом:
class <имя производного класса>:
<спецификатор><имя базового класса 1>,
<спецификатор><имя базового класса 2>,
…
<спецификатор><имя базового класса k>
{<список элементов производного класса>};
Рассмотрим пример. Задан производный класс D, который наследует элементы двух базовых классов B1 и B2.
#include <iostream.h>
class B1
{ protected:
int x;
public:
void showx()
{cout<<x<<’\n’;}
};
class B2
{ protected:
int y;
public:
void showy()
{cout<<y<<’\n’;}
};
class D: public B1, public B2
{public:
void setxy(int i, int j)
{x=i; y=j;}
};
void main()
{D object;
object.setxy(10,20);// элемент производного класса D
object.showx();// элемент базового класса B1
object.showy();// элемент базового класса B2
}
Замечания.
При создании объекта производного класса сначала вызывается конструктор базового класса, а за ним конструктор производного класса.
При разрушении объекта производного класса сначала вызывается его деструктор, а за ним деструктор базового класса.
Если производный класс наследует несколько базовых классов, то вызов конструкторов базовых классов, заданных в списке наследования, происходит слева – направо, а вызов деструкторов – справа – налево.
Например:
class D: public B1, public B2 {//элементы класса D};
Конструкторы: B1, B2, D.
Деструкторы: D, B2, B1.
4.При множественном наследовании никакой класс не может больше одного раза использоваться в качестве непосредственного базового.
Рассмотрим пример множественного наследования.
Задан производный класс, характеризующий окружность, вписанную в квадрат. Этот класс наследует свойства двух базовых классов, определяющих окружность и квадрат.
#include<conio.h>
#include<graphics.h>
class circ
{
int xc,yc,rc;
public:
circ(int xi, int yi, int ri)
{xc=xi;yc=yi;rc=ri;}
void draw()
{circle(xc, yc, rc);}//рисование окружности на экране
void hide()//гашение окружности
{ int bk, cc;
bk=getbkcolor();//возвращает цвет фона
cc=getcolor();//возвращает цвет изображения
setcolor(bk);
circle(xc,yc,rc);
setcolor(cc);//восстанавливает цвет изображения
}
};
class square
{
int xs,ys,ls;
public:
square(int xi, int yi, int li)
{xs=xi;ys=yi;ls=li;}
void drawsquare()
{ int d=ls/2;
line(xs-d,ys-d,xs+d,ys-d);
line(xs-d,ys+d,xs+d,ys+d);
line(xs-d,ys-d,xs-d,ys+d);
line(xs+d,ys-d,xs+d,ys+d);
}
void draw()
{drawsquare();}
void hide()
{int cc;
cc=getcolor();
setcolor(getbkcolor());
drawsquare();
setcolor(cc);
}
};
class circsquare: public circ, public square
{public:
circsquare(int xi,int yi,int ri):
circ(xi,yi,ri),
square(xi,yi,2*ri)
{}
void draw()
{circ::draw();
square::draw();
}
void hide()
{square::hide();
circ::hide();
}
};
void main()
{clrscr();
int dr=DETECT;
int dm;
initgraph(&dr,&dm,"C:\\BORLANDC\\BGI");
circsquare A(100,100,60);
circsquare B(400,300,50);
A.draw();
getch();
B.draw();
getch();
B.hide();
getch();
A.hide();
getch();
closegraph();
}