Занятие №8 ооп. Абстракция. Подведем краткие итоги после изучения виртуальных методов




Скачать 53.71 Kb.
Дата14.07.2016
Размер53.71 Kb.
Лабораторное занятие №8

ООП. Абстракция.

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

Правила использования виртуальных функций:


  1. Виртуальная функция может быть только методом класса

  2. Любую перегружаемую операцию-метод можно сделать виртуальной.

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

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

  5. Конструкторы не могут быть виртуальными.

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

Заметим, что существуют классы, которые выражают некоторую общую концепцию и применяются при определении данных и методов, которые будут общими для различных производных классов. Таковым является, например, класс Figure из предыдущего задания про «Цилиндры». Без описания виртуального метода GetVolume в базовом классе было бы весьма затруднительно корректно описать иерархию объектов – оснований цилиндра. Объекты класса Figure не имеют реального воплощения, а виртуальный метод нахождения площади фигуры GetVolume не имеет смысловой реализации. Было бы неправильно оставлять для пользователя возможность создавать объекты базового класса Figure. Для решения этой проблемы в С++ используются абстрактные виртуальные функции.

Абстрактной виртуальной называется функция, объявленная в базовом классе как виртуальная, но не имеющая описания. Для описания такой функции используется запись:



virtual <тип><имя функции>(<список параметров>)=0

Здесь «=0» является признаком абстракции виртуальной функции. При этом производный класс должен определить свою версию функции, так как просто использовать версию, определенную в базовом классе, нельзя.

Класс, который содержит, по крайней мере, одну абстрактную виртуальную функцию, называется абстрактным. Создание объектов абстрактного класса запрещено. Этот класс можно использовать только как базовый для создания других объектов.

Однако можно создавать указатели на объект абстрактного базового класса и применять его для реализации механизма полиморфизма.

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

class Figure{

public:

Figure();

virtual double GetArea()=0;

virtual Figure* Copy()=0;

virtual void Print()=0;

virtual ~Figure();

};

Опишем производные классы «Круг» и «Прямоугольник» и переопределим виртуальные методы для них.



class Circle:public Figure{

protected:

double* r;

int Init(double);

public:

Circle(double,int&);

virtual void Print();

virtual double GetArea();

virtual Figure* Copy();

virtual ~Circle();

};

class Rectangle:public Figure{

protected:

double* a;

double* b;

int Init(double,double);

public:

Rectangle(double,double,int&);

virtual void Print();

virtual double GetArea();

virtual Figure* Copy();

virtual ~Rectangle();

};После того, как созданы классы для оснований цилиндра, можно описывать объект «Цилиндр»:

class Cylinder{

double* h;

Figure* F;

int Init(double);

public:

Cylinder(Figure*,double,int&);

double GetVolume();

~Cylinder();

void Print();

};

Создавать новые объекты-цилиндры будем по алгоритму:



  1. Создаем объект-основание

  2. Передаем созданное основание в конструктор цилиндра

  3. Получаем новый цилиндр

Опишем виртуальные функции нахождения площади оснований:

double Circle::GetArea()

{

cout<<"double Circle::GetArea()\n";

return acos(-1)*(*r)*(*r);

}

double Rectangle::GetArea()

{

cout<<"double Rectangle::GetArea()\n";

return (*a)*(*b);

}

Опишем конструкторы и деструкторы классов для оснований цилиндров:



Rectangle::Rectangle(double a1,double b1, int& err)

{

cout<<"Rectangle::Rectangle(double a1,double b1, int& err)\n";

a=new double;

b=new double;

if(Init(a1,b1)==1) {err=1;delete this;}

else err=0;

}

int Rectangle::Init(double a1,double b1)

{

cout<<"int Rectangle::Init(double a1,double b1)\n";

if(a1>0 && b1>0) {*a=a1;*b=b1;return 0;}

else return 1;

}

Rectangle::~Rectangle()

{

cout<<"Rectangle::~Rectangle()\n";

delete a;

delete b;

}

Circle::Circle(double r1, int& err)

{

cout<<"Circle::Circle(double r1, int& err)\n";

r=new double;

if(Init(r1)==1) {err=1;delete this;}

else err=0;

}

int Circle::Init(double r1)

{

cout<<"int Circle::Init(double r1)\n";

if(r1>0) {*r=r1;return 0;}

else return 1;

}

Circle::~Circle()

{

cout<<"Circle::~Circle()\n";

delete r;

}

Опишем абстрактные функции:



Figure* Circle::Copy()

{

cout<<"Figure* Circle::Copy()\n";

int err=0;

Figure* F=new Circle(*(this->r),err);

if(!err){return F;}

else{return NULL;}

}

void Circle::Print()

{

cout<<"void Circle::Print()\n";

cout<<"\nInformation about Circle: r="<<*r<<"\n\n";

}

Figure* Rectangle::Copy()

{

cout<<"Figure* Rectangle::Copy()\n";

int err=0;

Figure* F=new Rectangle(*(this->a),*(this->b),err);

if(!err){return F;}

else{return NULL;}

}

void Rectangle::Print()

{

cout<<"void Rectangle::Print()\n";

cout<<"\nInformation about Rectangle: a="<<*a<<" b="<<*b<<"\n\n";

}

Опишем методы класса цилиндра:



Cylinder::Cylinder(Figure* Fl, double hl,int& err)

{

cout<<"Cylinder::Cylinder(Figure* Fl, double hl,int& err) \n";

F=Fl->Copy();

h=new double;

if(Init(hl)==0) err=0;

else{delete this; err=1;}

}

int Cylinder::Init(double h1)

{

cout<<"int Cylinder::Init(double hl) \n";

if(h1>0) {*h=h1; return 0;}

else return 1;

}

Cylinder::~Cylinder(){

cout<<"Cylinder::~Cylinder()\n";

delete h;

delete F;

}

double Cylinder::GetVolume(){

cout<<"Cylinder::GetVolume() \n";

return (*h)*F->GetArea();

}

void Cylinder::Print()

{

cout<<"void Cylinder::Print()\n";

cout<<"\nInformation about Cylinder: h="<<*h<<"\n foundation:\n";

F->Print();

}

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



int err=0;

int flag=0;

Figure* F;

while(flag==0)

{

cout<<"Enter type of object for creating: 1 - Circle, 2 - Rectangle\n";

cin>>flag;

}

if(flag==1)

{

F=new Circle(1.,err);

}

else

{

F = new Rectangle(10.,10.,err);

}

if(err==1)

{

F=NULL;

cout<<"ERRROR:F Incorrect object was deleted"<

}

else

{

cout<<"Object F was created"<

cout<<"\n Area: "<GetArea()<<"\n\n";

Cylinder* Cyl=new Cylinder(F,10,err);

if(err==0)

{

Cyl->Print();

cout<<"\n Cylinder's Volume: "<GetVolume()<<"\n\n";

delete Cyl;

Cyl=NULL;

}

else

{

Cyl=NULL;

cout<<"ERRROR:Cylinder Incorrect object was deleted"<

}

delete F;

F=NULL;

}



База данных защищена авторским правом ©uverenniy.ru 2016
обратиться к администрации

    Главная страница