Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

C++BUILDER и объектно-ориентированное программирование




1.1. Классы, компоненты и объекты

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

Свойства (properties) компонентов представляют собой расшире­ние понятия данных-членов и используют ключевое слово __ property для объявления. При помощи событий (events) компонент сообщает пользователю о том, что на нее оказано некоторое воздействие. Обработчики событий (event handlers) представляют собой методы, реализующие реакцию программы на возникновение событий. Типичные события – нажатие кнопки или клавиши на клавиатуре. Компоненты имеют ряд особенностей:

• Все компоненты являются прямыми или косвенными потомками класса TComponent. При этом иерархия наследования следующая: Tobject->Tpersistent-> Tcomponent->Tcontrol->….

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

• Компоненты размещаются только в динамической памяти с помощью оператора new.

• Компоненты можно добавлять к Палитре компонентов и манипулировать с ними посредством Редактора форм.

1.2. Разработка классов

C++Builder дает возможность объявить базовый класс, который инкапсулирует имена свойств, данных, методов и событий. Каждое объявление внутри класса определяет привилегию доступа к именам класса в зависимости от того, в каком разделе имя появляется. Каждый раздел начинается с одного из ключевых слов: private, protected и public, определяющих возможности доступа к элементам соответствующего раздела.

Рассмотрим пример объявления класса. Отметим объявление свойства Count в защищенном разделе, а метода SetCount, реализую­щего запись в данное Fcount, – в закрытом разделе.

class TPoint {

private:

int FCount; // Закрытый член данных

void __fastcall SetCount(int Value);

protected:

__property int Count = // Защищенное свойство

{ read= FCount, write=SetCount };

double x; // Защищенный член данных

double у; // Защищенный член данных

public:

TPoint(double xVal, double yVal); // Конструктор

double getX();

double getY();

};

Объявления класса и определения методов обычно хранятся в разных файлах (с расширениями.h и.срр, соответственно). Следующий пример показывает, если методы определяются вне класса, то их имена следует уточнять с помощью имени класса.

 

TPoint::TPoint (double xVal, double yVal)

{ // Тело конструктора

}

void __fastcall TPoint::SetCount(int Value){

if (Value!= FCount)

{

FCount = Value; // Запись нового значения

Update(); // Вызов метода Update

}

}

double TPoint::getX(){

// Тело метода getX(), объявленного в классе TPoint

}

1.3. Объявление производных классов

C++Builder дает возможность объявить производный класс, который наследует свойства, данные, методы и события всех своих предшественников в иерархии классов, а также может объявлять новые характеристики и перегружать некоторые из наследуемых функций. Объявление производного класса можно выполнить следующим образом:

class derivedClass: [<спецификатор доступа>] parentClass {

private:

<закрытые данные-члены>

<закрытые методы>

protected:

<защищенные данные-члены>

<защищенные методы>

public:

<открытые свойства>

<открытые данные-члены>

<открытые конструкторы>

<открытый деструктор>

<открытые методы>

__published:

<опубликованные свойства>

<опубликованные данные-члены>

<объявления дружественных функций>

};

 

Отметим появление нового раздела с ключевым словом __ published – дополнение, которое C++Builder вводит в стандарт ANSI C++ для объявления опубликованных элементов компонентных классов. Этот раздел отличается от раздела public только тем, что компилятор генерирует информацию RTTI (информация времени выполнения) о свойствах, данных-членах и методах объекта и C++Builder организует передачу этой информации Инспектору объектов.

Когда класс порождается от базового, все имена базового класса в производном классе автоматически становятся закрытыми по умолчанию (если спецификатор доступа при наследовании не указывается). Но это можно изменить, указав следующие спецификаторы доступа при наследовании базового класса:

• protected. Наследуемые (т.е. защищенные и открытые) имена базового класса становятся защищенными в экземплярах производного класса.

• public. Открытые имена базового класса и его предшественников будут открытыми в экземплярах производного класса, а все защищенные останутся защищенными.

Рассмотрим применение методики расширения и ограничения характеристик на примере создания разновидностей кнопки при наследовании базового компонента TButtonControl из Библиотеки Визуальных Компонентов. Базовый класс TButtonControl способен с помощью родительского метода Draw отображать кнопку в виде двух вложенных прямоугольников: внешней рамки и внутренней закрашенной области. Чтобы создать простую кнопку без рамки, нужно построить производный класс SimpleButton, использовав в качестве родительского TButtonControl, и перегрузить метод Draw:

 

class SimpleButton: public TButtonControl {

public:

SimpleButton(int x, int y);

void Draw();

~SimpleButton() { }

};

SimpleButton::SimpleButton(int x, int y): TButtonControl(x, y)

{ }

void SimpleButton::Draw()

{outline->Draw();}

 

Единственная задача конструктора объекта для SimpleButton – вызвать конструктор базового класса с двумя параметрами. Именно переопределение метода SimpleButton:: Draw () предотвращает вывод обводящей рамки кнопки (как происходит в родительском классе). Чтобы изменить код метода, надо изучить его по исходному тексту базового компонента TButtonControl.

Создадим кнопку с пояснительным названием. Для этого нужно построить производный класс TextButton из базового TButtonControl и перегрузить метод Draw с расширением его функциональности:

 

class Text {//Вспомогательный класс

public:

Text(int x, int y, char* string) { }

void Draw() { }

};

class TextButton: public TButtonControl {

Text* title;

public:

TextButton(int x, int y, char* title);

void Draw();

~TextButton() { }

};

TextButton::TextButton(int x, int y, char* caption):

TButtonControl(x, y) {

title = new Text(x, y, caption);

}

void TextButton::Draw () {

TButtonControl::Draw();

title->Draw();

}

1.4. Идентификация типов времени выполнения RTTI

Идентификация типов при выполнении программы RTTI (Run-Time Туре Identification) позволяет вам написать переносимую программу, которая способна определять фактический тип объекта в момент выполнения даже в том случае, если программе доступен только указатель на этот объект. Это дает возможность, например, преобразовывать тип указателя на базовый класс в указатель на производный тип фактического объекта данного класса. Таким образом, преобразование типов может происходить не только статически – на фазе компиляции, но и динамически – в процессе выполнения. Динамическое преобразование указателя в заданный тип осуществляется с помощью оператора dynamic_cast.

Механизм RTTI также позволяет проверять, имеет ли объект некоторый определенный тип, или принадлежат ли два объекта одному и тому же типу. Оператор typeid определяет фактический тип аргумента и возвращает указатель на объект класса typeinfo, который этот тип описывает.

Передавая RTTI Инспектору объектов во время выполнения, C++Builder информирует его о типах свойств и членов данного класса.

1.5. Пакеты

Пакеты – это особый тип динамических библиотек DLL для Windows. Как и обычные DLL, пакетные файлы BPL (Borland Package Library) содержат код, разделяемый многими приложениями. C++Builder размещает наиболее часто используемые компоненты в пакете под названием VCL50.BPL. При создании исполняемого кода приложения в нем остаются только уникальные инструкции и данные, а разделяемый код подгружается из указанных пакетов во время ис­полнения.

Объявление нового компонентного класса в интерфейсном модуле должно включать предопределенный макрос PACKAGE сразу же за ключевым словом class:

class PACKAGE MyComponent:...

Этот же макрос должен присутствовать в кодовом модуле там, где объявлена функция регистрации компонента:

void __fastcall PACKAGE Register(){…}

Образующийся при подстановке макроса PACKAGE код обеспе­чивает возможность импортирования и экспортирования объявлен­ного компонентного класса в результирующий файл с расширением BPL. Если при создании нового компонента вы пользуетесь мастером (по команде Component | New Component), C++Builder автоматически вводит PACKAGE в нужное место.

1.6. Объявления компонентных классов

Опережающие объявления классов Библиотеки Визуальных Ком­понентов VCL, входящей в состав C++Builder, используют модификатор _declspec:

_declspec (<спецификатор>)

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

delphiclass используется для опережающего объявления прямых или косвенных производных от VCL-класса TObject;

delphireturn используется для опережающего объявления прямых или косвенных производных от VCL-классов Currency, AnsiString, Variant, TDateTime и Set. Он определяет правила совместимости VCL при обращении с параметрами и возвращаемыми значениями функ­ций-членов.

pascalimplementation указывает, что компонентный класс реали­зован на Объектном Паскале.

1.7. Объявления свойств

C++BuiIder использует модификатор _ property для объявления свойств компонентных классов. Синтаксис описания свойства имеет вид:

_property <тип свойства> <имя свойства> = {<список атрибутов>};

Список атрибутов содержит перечисление следующих атрибутов свойства:

write = < член данных или метод записи > – определяет способ присваивания значения члену данных;

read = < член данных или метод чтения > – определяет способ по­лучения значения члена данных;

default = < булева константа > – разрешает или запрещает сохране­ние значения свойства по умолчанию в файле формы *.dfm;

stored = < булева константа или функция > – определяет способ со­хранения значения свойства в файле формы с расширением *.dfm.

C++BuiIder использует модификатор __published для специфика­ции тех свойств компонентов, которые будут отображаться Инспекто­ром объектов на стадии проектирования приложения. Правила види­мости, определяемые этим ключевым словом, не отличаются от пра­вил видимости членов данных, методов и свойств, объявленных как public.

1.8. Объявления обработчиков событий

C++Builder использует модификатор _ closure для объявления функций обработчиков событий:

<тип> (_ closure * <name>) (<список параметров>)

Это ключевое слово определяет указатель функции с именем name. В отличие от 4-байтового указателя обычной функции, 8-байтовый указатель _ closure передает еще и скрытый указатель this на экземп­ляр класса.

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

1.9. Право владения

Любой компонент может находиться во владении (ownership) дру­гих компонентов. Свойство компонента Owner (Владелец) содержит ссылку на компонент, который им владеет. Владелец отвечает за ос­вобождение тех компонентов, которыми владеет, когда сам разруша­ется. Так, в процессе конструирования формы она автоматически ста­новится владельцем всех компонентов, размещенных на ней, даже если часть их размещена на другом компоненте, например, таком как TPanel. Владение применимо не только к видимым, но и к невидимым (TTimer, TDataSource) компонентам.

Когда компонент не переносится на форму, а создается динамически в процессе выполнения программы, конструктору компонента передается ее владелец в каче­стве параметра. В следующем примере неявный владелец (например, форма) передается конструктору компонента TButton как параметр. Конструктор TButton выполнит присваивание значения переданного параметра свойству Owner кнопки MyButton:

MyButton = new TButton(this);

Когда форма, уничтожается, автоматически уничтожается и кнопка MyButton.

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

Свойство Components класса Tcomponent содержит перечень компонен­тов, которыми владеет данный компонент. Ниже приводится фраг­мент кода обработчика события OnClick с циклом отображения имен классов всех компонентов, которыми владеет некоторая форма.

void __fastcall TForm1::Button1Click(TObject *Sender)

{

for (int i=0; i<ComponentCount; i++){

ShowMessage(Components[i]->ClassName());

ShowMessage(Components[i]->ClassParent()->ClassName());

}

}

 

Метод ClassParent() возвращает родительские классы для находящихся на форме классов.

1.10. Родительское право

Понятие родительского права (parentship) отличается от права владения и применимо только к видимым компонентам. В качестве родительских компонент могут выступать форма, панель, groupbox, на которых располагаются объекты – потомки. Родительские компоненты обращаются к соответствующим внутренним функциям, чтобы вызвать отображение компонентов-потомков. Родитель также отвечает за освобождение своих потомков, когда сам родитель уничтожается. Свойство компонента Parent (Родитель) содержит ссылку на компо­нент, который является его родителем. Многие свойства видимых компонентов (например, Left, Width, Top, Height) относятся к роди­тельским элементам управления. Другие свойства (например, ParentColor и ParentFont) позволяют потомкам использовать свойства родителей.

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

void __fastcall TForm1::FormCreate(TObject *Sender)

{

MyEdit = new TEdit(this); // Передать this как владельца

MyEdit->Parent = this; // Передать this как родителя

}

В качестве примера приведем объявление компонента с единственным свойством IsTrue, имеющим значение по умолчанию true, а также конструктор, который устанавливает это значение при инициализации компонентного объекта. Заметим, что если свойство имеет значение по умолчанию false, то не нужно явно устанавливать его в конструкторе, поскольку все объекты (включая компоненты) всегда инициализируют свои члены данных значением 0, т.е. false.

 

class TMyComponent: public TComponent

{ private:

Boolean FIsTrue;

public:

__fastcall TMyComponent(TComponent* Owner);

__published:

__property Boolean IsTrue =

{ read=FIsTrue, write=FIsTrue, default=true };

};

__fastcall TMyComponent:: TMyComponent (TComponent* Owner): TComponent (Owner) { FIsTrue = true; }

Вопросы

1. Каким образом, и в каких файлах можно создать собственный класс, динамический объект и вызвать методы класса?

2. Что представляют собой свойства компонентов? Приведите примеры нескольких свойств формы.

3. Что представляют собой события компонентов? Приведите примеры.

4. Каким образом можно изменить значения свойств компонентов?

5. Объявить класс MyClass, содержащий некоторую строку, и метод swap(), заменяющий строку другой строкой. Выполнить тестирование.

6. Объявить класс и определить размерность объектов данного класса.

7. Чем отличаются оператор-функции, объявленные как friend, от оператор-функций членов класса C++ и можно ли их использовать в C++Builder?

8. На каком этапе происходит выделение памяти под объекты компонентных классов?

9. Что представляет собой общедоступное свойство класса и его опубликованное свойство?

10. Что поизойдет в результате выполнения следующего кода?

 

void __fastcall TForm1::Button1Click(TObject *Sender)

{

TForm * newForm= new TForm(this);

TButton* button=new TButton(Application);

button->Parent=newForm;

button->Caption="New Button";

button->Left=10;

button->Top=15;

button->Show();

newForm->Caption="newForm";

newForm->ShowModal();

button->Click();

delete newForm;

}

 

12. Как распознать нажатые функциональные клавиши?

13. Куда поступают события клавиатуры? Какое свойство формы влияет на то, куда поступают события клавиатуры?

14. В следующем коде какой из объектов отвечает за удаление кнопки?

 

TButton* B=new TButton(this);

B->Parent=Panel1;




Поделиться с друзьями:


Дата добавления: 2014-12-27; Просмотров: 2243; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.081 сек.