Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП_Лекции 2010.doc
Скачиваний:
69
Добавлен:
17.03.2015
Размер:
954.37 Кб
Скачать

1. Динамическая проверка типа объекта:

if Sender is TButton... if(dynamic_cast<TButton*>(Sender))

{is при неудаче возвращает false, /* dynamic_cast при неудаче

а при удаче - true} возвращает NULL,a при удаче -

указатель */

2. Динамическое переопределение типа объекта:

b := Sender as TButton; TButton& ref_b = dynamic_cast

{при неудаче генерируется <TButton&> (*Sender); /* при

исключение} неудаче генерируется исключение*/

3. Динамическое определение типа объекта:

Sender.ClassName typeid(*Sender).пате();

Метод TObject.ClassName, который возвращает строку, содержащую имя реального типа объекта независимо от типа используемой переменной, имеет аналог в C++ - name(). Остальные методы аналогов не имеют, но они описаны в TObject как общедоступные и потому могут вызываться напрямую (см. § 5.4).

Обработка исключений VCL-совместимых классов. VCL-совмести-мые классы используют механизм обработки исключений Delphi Pascal. Стандартная обработка предполагает, как правило, вывод сообщений об ошибках.

C++ Builder включает классы для автоматической обработки таких исключительных ситуаций, как деление на нуль, ошибки операций с файлами, неверное преобразование типа и т. п. Все эти классы наследуются от класса Exception (см. § 5.8). Для перехвата этих исключений используется конструкция C++:

catch (<класс исключения> <&<переменная>)

Переменная, как это и принято в C++, используется для получения значений полей класса и вызова его методов, например:

void __fastcall TForm1:: ThrowException(TObject *Sender)

{try

{ throw Exception("VCL component"); }

catch(const Exception &E)

{ShowMessage(AnsiString(E.ClassName())+ E.Message); }

}

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

Наиболее часто используемые классы исключений перечислены в § 5.8.

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

Необходимо хорошо представлять себе различие между исключениями C++ и исключениями VCL:

  1. Если при конструировании объекта возникает исключение, то в C++ деструкторы вызываются только для полей и базовых классов, которые были полностью сконструированы, а в VCL - в том числе и для объекта, при конструировании которого обнаружено исключение.

  2. В C++ исключения могут перехватываться по ссылке, указателю или значению, а в VCL - только по ссылке или по значению. Попытки перехвата по значению приводят к синтаксической ошибке. Исключения от схем контроля или операционной системы, такие, как EAccessViolation, могут перехватываться только по ссылке.

  3. Для исключений, перехваченных по ссылке, нельзя повторно генерировать throw. Последнее связано с тем, что как только исключение операционной системы или VCL распознается как исключение C++, оно уже не может быть повторено в своем качестве из блока catch.

  4. Программист не должен освобождать память объекта исключения VCL после обработки исключения.

  5. Генерация исключений VCL выполняется «по значению».

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

try{ char *p = 0; *р = 0;}

catch (const EAccessViolation &e)

{<обработка исключения>}

В качестве примера разработки VCL-совместимого класса рассмотрим проектирование главного окна приложения.

Рис. 6.2. Главное окно приложения «Динамический массив»

Пример 6.7. Разработка VCL-coвместимого класса для реализации главного окна приложения «Динамический массив». Главное окно приложения «Динамический массив» должно обеспечивать возможность тестирования всех предусмотренных операций над массивом (рис. 6.2).

В процессе визуального проектирования C++ Builder автоматически строит описание класса TMainForm, куда добавляются поля-указатели на визуальные компоненты и прототипы методов обработки событий, используемых программистом для реализации данного приложения. Это описание помещается в файл Main.h:

#iinclude <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

#include <ExtCtrls.hpp>

#include <Grids.hpp>

class TMainForm : public TForm

{

__published // опубликованные компоненты класса

TLabel *MaxSizeI.abel; // метка Максимальный размер массива

TEdit *MaxSizeЈdit; // редактор Максимальный размер массива

TBevel *Bevel1; // рамка

TButton *ModifyButton; // кнопка Изменить

TButton *InsertButton; // кнопка Вставить

TButton *DeleteButton; // кнопка Удалить

TButton *DataButton; // кнопка Изменить данные

TButton *ExitButton; // кнопка Выход

TStringGrid *DataStringGrid; // таблица для отображения вектора

TLabel *IndexLabel; // метка Индекс

TLabel *ValueLabel; // метка Значение

TEdit *IndexEdit; // редактор индекса

TEdit *ValueEdit; // редактор значения

TLabel *CommentLabel; // метка Комментарий

void __fastcall ExitButtonClick(TObject Sender); /* обработчик события "Нажатие на кнопку Выход" */

void __fastcall ModifyButtonClick(TObject *Sender); /* обработчик события "Нажатие на кнопку Изменить" */

void __fastcall DataStringGridKeyPress(TObject *Sender, char &Key);

/* обработчик события "Ввод символа" */

void __fastcall InsertButtonClick(TObject *Sender); /* обработчик события "Нажатие на кнопку Вставить" */

void__fastcall DeleteButtonClick(TObject *Sender); /* обработчик события "Нажатие на кнопку Удалить" */

void __fastcall DataButtonClick(TObject *Sender); /* обработчик события "Нажатие на кнопку Изменить данные" */

void __fastcall FormActivate(TObject *Sender); /* обработчик события "Активация формы" */

private: // внутренние компоненты класса

public: // общедоступные компоненты класса

__fastcall TMainForm(TComponent* Owner); // конструктор

__fastcall ~TMainForm(); // деструктор

};

extern PACKAGE TMainForm *MainForm; #endif

Тела обработчиков событий программируются в файле Main.cpp. Наиболее интересные фрагменты текста программы выделены (работа с множествами Delphi Pascal, обработка исключений различных типов, проверка кода нажатой клавиши, работа со строками AnsiString, динамическая проверка типа и т. п.):

#include <vcl.h>

t#pragma hdrstop

#include "Array.h"

#include "Main.h"

#pragma package(smart_init)

#pragma resource "*.dfm"

TMainForm *MainForm;

TMasByte*A;

__fastcall TMainForm:;TMainForm(TComponent* Owner): TForm(Owner)

{A=new TMasByte(lO);}

__fastcall TMainForm::~TMainForm() { delete A;}

void __fastcall TMainForm::ExitButtonClick(TObject *Sender) { Close(); }

void __fastcall TMainForm::ModifyButtonClick(TObject *Sender)

{ short Ind; unsigned char Value; AnsiStringNum("uндeксa");

TMsgDlgButtons Setl; Setl<<mbOK; // объявить множество

try {Ind=StrToInt(IndexEdit->Text); //выполнить, контролируя исключения

Num="элемента ";

Value =StrToInt(ValueEdit- > Text) ;

A~>Modify(Ind, Value);

A->OutputMas(DataStringGrid, 0,0); }

catch (EConvertError&) /* перехватить исключение "Ошибка преобразования" */

{AnsiString s="Heвepнo введено значение ";

MessageDlg(s+Num,mtInformation,Set1, 0); }

catch (char * Mes) /* перехватить исключения от операций над динамическим массивом */

{ MessageDlg(Mes, mtInformation, Set1, 0);}

}

void __fastcall TMainForm::DataStringGridKeyPress(TObject *Sender, char &Key)

{ if (Key==VK_RETURN) // если нажата клавиша Enter

{Key=0;

try {A->lnputMas(DataStringGrid, 0,0);

TGridOptions Set1; // объявить множество

Set1 -DataStringGrid- > Options;

Set1>>goEditing>>goAlwaysShowEditor>>goTabs;

DataStringGrid->Options=Set1;

DataStringGrid->Enabled=false;

ModifyButton~>Enabled=true;

InsertButton->Enabled=true;

DeleteButton->Enabled=true;

DataButton->Enabled=true;

IndexEdit->SetFocus();

DataStringGrid->Col=0;

CommentLabel-> Visible=false; }

catch (char* Mes)

{ TMsgDlgButtons Set2; // объявить множество

Set2<<mbOK; MessageDlg(Mes,mtlnformation,Set2,0);}

}

}

void __fastcall TMainForm::lnsertButtonClick(TObject *Sender)

{ short Ind;

unsigned char Value;

AnsiString Nит("индекса");

TMsgDlgButtons Set1;

Setl<<mbOK;

try {Ind=StrToInt(IndexEdit->Text); /* выполнить, контролируя исключения */

Num="элемента ";

Value =StrTolnt(ValueEdit-> Text);

A->Insert(Ind, Value);

A->OutputMas(DataStringGrid, 0,0); }

catch (EConvertError&) /* перехватить исключение "Ошибка преобразования" */

{AnsiString s="Неверно введено значение ";

MessageDlg(s+Num, mtInformation,Setl, 0); }

catch (char * Mes) /* перехватить исключения от операций над динамическим массивом */

{ MessageDlg(Mes,mtInformation,Setl,0); }

}

void __fastcall TMainForm::DeleteButtonCtick(TObject *Sender)

{ short Ind; TMsgDlgButtons Set1;

Setl<<mbOK;

try {Ind=StrToInt(IndexEdit-> Text);

A->Delete(Ind);

A->OutputMas(DataStringGrid,0,0); }

catch (EConvertError&)

{ MessageDlg("Неверно введено значение индекса.", mtlnformation,Set 1,0);}

catch (char * Mes)

{MessageDlg(Mes,mtInformation,Setl,0); }

}

void __fastcall TMainForm::DataButtonClick(TObject *Sender)

{ FormActivate(DataButton);}

void __fastcall TMainForm::FormActivate(TObject *Sender)

{ CommentLabel-> Visible=true;

if (dynamic_cast<TButton*> (Sender)) // если отправитель - кнопка, то

{for (int i=0;i<10;i++) DataStringGrid->Cells[i][0]="";

TGridOptions Setl; Setl =DataStringGrid->Options;

Setl << goEditing<<goAlwaysShowEditor<<go Tabs;

DataStringGrid->Options =Setl;

DataStringGrid->Enabled=true;

DataStringGrid->Col=0;

DataStringGrid->SetFocus();

delete A;

A=new TMasByte(10); /* пересоздать вектор */ }

}