Студопедия

КАТЕГОРИИ:


Архитектура-(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)

Открытие потока

Ввод-вывод потока.

Работа с дисками.

Библиотека Си поддерживает следующие три уровня ввода-вывода:

- ввод-вывод потока;

- ввод-вывод нижнего уровня;

- ввод-вывод для консоли и порта.

 

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

Ввод вывод потока позволяет:

- открывать и закрывать потоки;

- создавать и удалять временные потоки;

- читать и записывать символ;

- читать и записывать строки;

- читать и записывать форматированные данные;

- читать и записывать неформатированные данные;

- анализировать ошибки ввода-вывода потока и условия конца потока (конца файла);

- управлять буферизацией потока и размером буфера;

- выгружать буфера, связанные с потоками;

- получать и устанавливать указатель текущей позиции в потоке.

 

Чтобы использовать функции ввода-вывода потока в программе

необходимо директивой #include включить файл stdio.h. Этот файл содержит объявления функций ввода-вывода, а также определения констант, типов и струк4тур, используемых фунциями потока.

 

 

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

Для открытия потока библиотека Си представляет три функции: fopen и fdopen открывают потоки, а freopen переназначает указатель на другой поток.

При успешном открытии потока функции открытия возвращают указатель на структуру FILE, в противном случае возвращается нулевой указатель (NULL).

#include <stdio.h>

FILE *file_ptr;

if(file_ptr=fopen(…)== NULL)

printf(“\n Ошибка открытия файла”);

 

Тип доступа к потоку задаётся как аргумент функции открытия. Он является строковым литералом, который может принимать значения:

“r” - поток открывается для чтения;

“w” - открывается пустой поток для записи. Если поток

существует, его содержимое пропадает;

“a” - поток открывается для записи в конец потока. Если поток

не существует, он создаётся;

“r+” - поток открывается для чтения и записи (поток должен

существовать);

“w+” - открывается пустой поток для чтения и записи. Если

поток существует, его содержимое пропадает;

“a+” - поток открывается для чтения и записи в конец

потока. Если поток не существует, он создаётся.

#include <stdio.h>

FILE *file_ptr;

if(file_ptr=fopen(“a:file.dat”,”r”)== NULL)

printf(“\n Ошибка открытия файла”);

else

printf(“\n Файл открыт для чтения”);

 

Операции чтения и записи для потока начинаются с текущей позиции потока, определяемой указателем текущей позиции в потоке.

Библиотека Си предоставляет следующие функции для позиционирования указателя текущей позиции в потоке:

ftell(fp) и fgetpos получают текущую позицию указателя потока

fseek и fsetpos устанавливают текущую позицию указателя в потоке

rewind(fp) позиционирует указатель потока на начало потока.

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

SEEK_SET - начало потока,

SEEK_CUR – текущая позиия указателя потока,

SEEK_END – конец потока.

 

ПРИМЕР использования функции fseek

 

FILE *fp;

long n;

fseek(fp,0L, SEEK_SET);//Позиционирование на начало потока

fseek(fp,0L, SEEK_END); //Позиционирование на конец потока

fseek(fp,n, SEEK_SET); //Позиционирование на n

//байт от начала потока

fseek(fp, n, SEEK_END); //Позиционирование на n

//байт от конца потока

 

fseek(fp, n, SEEK_CUR); //Позиционирование на n

//байт от текущей позиции

 

fseek(fp,- n, SEEK_CUR); //Позиционирование на n

//байт до текущей позиции

fseek(fp,- n, SEEK_ END); //Позиционирование на n

//байт до конца потока

 

Пример

Пусть имеется структура

 

sruct h_main

{

int tipe;

char s[20];

char s2[20];

char s[320];

}

 

 

sruct h_main m;

//позиционирование курсора на начало i–й записи структуры в файле

 

fseek(fmain, i*sizeof(m), SEEK_SET);

чтение

fread(&m, i*sizeof(m), 1, fmain);

запись

fwrite(&m, i*sizeof(m), 1, fmain);

Операции динамического распределения памяти.

Операции new, new[ ],delete, delete[ ] введены в язык С++ с целью решения одной из задач управления памятью, а именно – её динамического распределения. Две операции new, new[ ] предназначены для выделения участков свободной памяти и размещения в них переменных (new[ ] – массивов). Продолжительность существования таким образом созданных (динамических) переменных – от точки создания до конца программы или до явного освобождения соответсвующего участка памяти применением операций delete (delete[] – для удаления массивов).

Первая из рассматриваемых операций предназначена для размещения в динамической памяти переменной заданного аргументом типа (кроме типов массивов) и имеет следующий общий тип

new имя_типа или new имя_типа(выражение)

Вторая форма помимо выделения памяти осуществлвяет её инициализацию значением выражения. В обоих случаях результат операции имеет тип указателя того же типа что и аргумент, (т.е. имя_типа), и значение адреса размещенной динамической переменной. Это значение, очевидно, нужно сохратить в какой-либо переменной-указателе, что обеспечит в дальнейшем доступ к динамической переменной.

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

int *i = new int, *j = new(5);

*i=*j**j;

Для размещения динамических массивов предусмотрена специальная операция new[ ], вызываемая следующим образом:

new тип_элемента[размер ]... [размер]

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

Пример размещения в памяти трехмерного динамического массива

long (*p) [3][4]; // описание указателя

p=new long [2][3][4]; // размещение массива

p[1][1][1]=1; // обращение к элементу

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

delete i; delete j; delete[] p;

Создание многомерных динамических массивов с переменным количеством элементов

double **a=new double *[n];

for(int i=0; i<n;i++) a[i]=new double[m];

a[1][1]=1.0;

for(int i=0; i<n;i++) delete[] a[i]; delete[] a;

ОБЪЕКТНО−ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ

Принципы объектно-ориентированного программирования

Объектно-ориентированное программирование (ООП) представляет собой подход к программированию. По мере развития вычислительной техники и усложнения решаемых задач возникали различные модели (т.н. парадигмы) программирования. Первые компиляторы (к ним прежде всего относится компилятор языка FORTRAN) поддерживали процедурную модель программирования, в основе которой лежит использование функций. Используя процедурную модель программирования, программисты могли писать программы до нескольких тысяч строк длиной. Следующий этап развития связан с переходом к структурной модели программирования (реализованной в компиляторах языков ALGOL, Pascal и С). Сутью структурного программирования является представление программы в виде совокупности взаимосвязанных процедур (или блоков) и тех которыми эти процедуры (или блоки) оперируют. При этом широко используются программные блоки и допускается только минимальное использование операторов GOTO. Сопровождение таких программ намного проще, чем процедурно-сориентированных. Используя структурное программирование, Передний программист может создавать и сопровождать программ до нескольких десятков тысяч строк длиной. Для написания более сложных задач понадобился новый подход к программированию, который и был реализован в модели ООП. Модель ООП основана на нескольких основополагающих концепциях.

Абстракция данных — это возможность определять новые типы данных, с которыми можно работать почти так же, как и с.основными типами данных. Такие типы часто называются абст­рактными типами данных, хотя термин «типы данных, опреде­ляемые пользователем» является более точным.

Инкапсуляция — это механизм, который объединяет данные и код, манипулирующий этими данными, а также защищает то и другое от постороннего вмешательства.

Для реализации этих двух основополагающих концепций в языке C++ используются классы. Термином класс определяется тип объек­тов. При этом каждый представитель (или экземпляр) класса назы­вается объектом. Каждый объект всегда имеет свое, уникальное состояние, определяемое текущими значениями его данных-членов (элементов-данных). Функциональное назначение класса определя­ется возможными действиями над объектами класса, которые зада­ются его функциями-членами (функциями-элементами или метода­ми). Причем термин «метод» чаще используется в литературе, по­священной языку Object Pascal. В каждом классе распределяется память для хранения данных, и устанавливаются допустимые опера­ции для каждого объекта данных данного типа. Создание объектов данного класса производится специальной функцией-членом, кото­рая называется конструктором, а уничтожение — другой специаль­ной функцией-членом, которая называется деструктором. Класс позволяет делать недоступными внутренние данные, представляя их как открытые (public), закрытые (private) и защищенные (protected). Класс устанавливает четко определенный интерфейс для взаимодействия объектов этого типа с остальным миром. Закры­тые коды или данные доступны только внутри этого объекта. С дру­гой стороны, открытые коды н данные, несмотря на то, что они за­даны внутри объекта, доступны для всех частей программы. Откры­тая часть объекта как раз и используется для создания интерфейса объекта с остальным миром. Полученными объектами можно управлять при помощи сообщений (или запросов), которые пред­ставляют собой просто вызовы функций-членов. Мы будем пользо­ваться термином запрос, чтобы не путать это понятие с сообщения­ми операционной системы Windows.

Наследование — это процесс, посредством которого один объ­ект может приобретать свойства другого. Это означает, что в ООП на основе уже существующих классов можно строить про­изводные классы. При этом производный класс (называемый так­же классом-потомком) наследует элементы-данные и функции-члены от своих родительских классов {классов-предков), добав­ляя к ним свои, которые позволяют ему реализовать черты, ха­рактерные только для него. Защищенные данные-члены и функ­ции-члены родительского класса доступны из производного клас­са. Кроме того, в производном классе наследуемые функции мо­гут быть переопределены. Таким образом, можно построить це лую иерархию классов, связанных между собой отношением ро­дитель — потомок. Термин базовый класс используется как сино­ним родительскому классу в иерархии классов. Если объект на­следует свои атрибуты (данные-члены и функции-члены) от од­ного родительского класса, говорят об одиночном (или простом) наследовании. Если объект наследует атрибуты от нескольких родителей, говорят о множественном наследовании. Наследова­ние позволяет значительно сократить определение класса-потомка благодаря тому, что классы-потомки являются расшире­ниями родительских классов.

Полиморфизм (от греческого "polymorphos" -.множествен­ность форм) — это свойство кода вести себя по-разному, в зави­симости от ситуации, возникающей в момент выполнения. Поли­морфизм — это не столько характеристика объектов, сколько ха­рактеристика функций-членов класса и проявляется, в частности, в возможности использования одного имени функции-члена для функций, имеющих различные типы аргументов, если выполняе­мые функцией действия определяются типом переданных ей ар­гументов. Это называется перегрузкой функции. Полиморфизм может применяться и к операциям, то есть выполняемые опера­цией действия также могут зависеть от типа данных (операндов). Такой тип полиморфизма называется перегрузкой операции.

В более общем смысле полиморфизм — это способность объектов различных классов отвечать на запрос функции сообразно типу своего класса. Другими словами, полиморфизм — это способность указателей (или ссылок) на базовый класс принимать формы при использовании их для вызовов виртуальных функций. Такая возможность в C++ является результатом него связывания. При позднем связывании адреса вызываемых функций-членов определяются динамически во время выполнения программы, а не статически во время компиляции, как в традиционных языках, в которых применяется раннее связывание. Позднее связывание выполняется только для виртуальных функций.

Теперь, когда мы рассмотрели основные концепции ООП, мы остановиться

на методологии ООП. В этой методологии задача представляется не в виде алгоритмической модели, а в виде совокупности объектов различных классов, которые обмениваются запросами. Объект, получивший запрос, отвечает на него посредством вызова соответствующей функции. Нахождение общности между типами объектов задачи — не простой процесс. Он осуществляется на стадии объектно-ориентированного проектирования. На этой стадии внача­ле рассматривается вопрос о применимости ООП к решаемой задаче. При этом для принятия решения о применимости ООП решающую роль играет та степень общности между классами, которую можно использовать, применяя механизмы наследова­ния и виртуальные функции. В некоторых задачах, таких как разработка графического интерфейса приложения, разработка приложений баз данных и компьютерная графика, простор для ООП поистине безграничен. Кроме того, методы ООП позволяют скрыть детали низкоуровневых сетевых протоколов. Поэтому они широко применяются при программировании приложений, рабо­тающих в сетях (как локальных, так и глобальных, например, в Internet). В случае принятия решения о применимости ООП на следующем этапе проектирования разрабатываются классы как строительные блоки для других типов и изучаются возможности выделения в классах тех свойств, которые могут быть переданы базовому классу. Затем проектируются те запросы, которыми будут обмениваться объекты, и осуществляется реализация раз­работанных объектов и запросов.

Классы

Понятие класса является наиболее важным в языке C++. Синтаксис описания класса похож на синтаксис описания структуры. Вот его основная форма:

class <имя_класса> {

//закрытые функции-члены и данные-члены

//класса

public:

//открытые функции-члены и данные-члены

//класса } <список_объектов>;

В описании класса <список_объектов> не является обя­зательным. Можно объявить объекты класса позже, по мере необходимости. Так обычно и поступают. Хотя <имя_класса> также необязательно, его обычно указывают. Причина в том, что <имя_класса> становится новым именем типа данных, кото­рое используется для объявления объектов этого класса.

Функции и переменные, объявленные внутри объявления (класса), становятся членами этого класса. Переменные, объявленные внутри объявления класса, называются данными-членами этого класса; функции, объявленные внутри объявления класса, называются функциями-членами класса. По умолчанию, все функции и переменные, объявленные в классе, становятся закрытыми для этого класса. Это означает, что они доступны только для других членов этого класса. Для объявления открытых членов класса используется ключевое слово public, за которым следует двоеточие. Все функции и переменные, объявленные после слова public, доступны и для других членов класса, и для в любой другой части программы, в которой содержится класс. Вот пример объявления класса:

class AnyClass {

//закрытый элемент класса int a; public:

int get_a();

void set_a(int num);

Хотя функции get_a() и set_a() и объявлены в классе AnyClass, они еще не определены. Для определения функции-члена нужно связать имя класса, частью которого является функция-член, с именем функции. Это достигается путем написания имени функции вслед за именем класса с двумя двоеточиями. о, записываемую в виде двух двоеточий, называют операцией расширения области видимости. Для задания функции используется следующая общая форма:

<Тип> <имя__класса>::<имя_фунхции>

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

{ //тело функции

Ниже приведены примеры определения функций-членов get_a()

и set_a():

void AnyClass::get_a()

{

return a; }

int AnyClass::set_a(int num)

{

a = num;

}

Объявление класса AnyClass не приводит к созданию объ­ектов типа AnyClass. Чтобы создать объект соответствующего класса, нужно просто использовать имя класса как спецификатор типа данных. Например,

AnyClass obi, оb2;

После того, как объект класса создан, можно обращаться к от­крытым членам класса, используя операцию "точка", так же как к полям структуры.

Например,

obl.set_a(10); ob2.set_a(37);

Эти операторы устанавливают значения переменной а в объ­ектах оb1 и оb2. Каждый объект содержит собственную копию всех данных, объявленных в классе. Это значит, что значение переменной а в оb1 отлично от значения этой переменной в оb2.

Доступ к элементам данных класса можно получить и с по­мощью указателя на объект этого класса. Следующий пример это иллюстрирует.

class Coord

{

public: int x,y; void SetCoord(int _x, int _y);

void

Coord::SetCoord(int _x, int jy)

{ x = _x;

у= _ у;

}

int main ()

{

Coord pt; Coord *ptPtr = &pt; //указатель на объект

//...

pt.x = 0; //объект.член_класса

ptPtr->y =0; //указатель->член_класса

ptPtr->SetCoord(10,20);

//...

return 0;

}

Среди программистов часто возникает спор о том, какой метод доступа к членам класса - через оператор "." или через оператор "->" - работает быстрее. Внесем ясность в этот вопрос, выбора члена "." работает в точности так же, как оператор "->", за исключением того, что имени объекта предшествует неявно сгенерированный компилятором оператор адреса "&".

Таким образом, инструкцию

ObjName.FuncName();

компилятор трактует, как

(&ObjName)->FuncName();

Имена элементов класса могут также использоваться с именем класса, за которым следует операция разрешения видимости (двойное двоеточие), то есть вызов элемента имеет вид:

<имя_класса>::<имя_члена>

Подробнее эту форму вызова элементов класса мы рассмотрим позднее.

Язык C++ накладывает определенные ограничения на данные-члены класса:

· данные-члены не могут определяться с модификаторами auto, extern или register;

· данным-членом класса не может быть объект этого же класса (однако данным-членом может быть указатель или ссылка на объект этого класса, или сам объект друго­го класса).

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

Класс должен быть объявлен до использования его членов. Однако иногда в классе должен быть объявлен указатель или ссылка на объект другого класса еще до того, как он определен. В этом' случае приходится прибегать к неполному объявлению класса, которое имеет вид:

class <имя_класса>;

Рассмотрим пример.

//Неполное объявление класса

class PrevDecl;

class AnyClass

{

int x;

PrevDecl* obPtr;

public:

AnyClass(int _x){x = _x;

};

int main()

{

//...

return 0;

}

 

//Полное объявление класса

class PrevDecl

{

int a;

public:

PrevDecl();

};

Нельзя создать объект не полностью определенного класса. Попытка создания такого класса приводит к ошибке компиляции.

Заметим, что определение класса напоминает определение структуры, за исключением того, что определение класса:

· обычно содержит один или несколько спецификаторов доступа, задаваемых с помощью ключевых слов public, protected или private;

· вместо ключевого слова struct могут применяться
class или union;

· обычно включает в себя наряду с элементами данных
функции-члены;

· обычно содержит некоторые специальные функции-
члены, такие, как конструктор и деструктор.

Ниже приведены примеры определения классов с использованием ключевых слов struct и union.

struct Point

{

private:

int x;

int y;

public:

int GetXO;

int GetY();

void SetX(int _x);

void SetY(int _y);

};

union Bits

{

Bits(unsigned int n);

void ShowBits();

unsigned int nun;

unsigned char с[sizeof(unsigned int)];

};

Спецификатор доступа применяется ко всем элементам класса, следующим за ним, пока не встретится другой спецификатор или не закончится определение класса. Следующая таблица описывает три спецификатора доступа.

 

Таблица Спецификаторы доступа к классу

 

Спецификатор Описание
private: Данные-члены и функции-члены доступны только для функций-членов этого класса.
Спецификатор Описание
Protected: Данные-члены и функции-члены доступны для функций-членов данного класса и классов, производных от него.
public: Данные-члены и функции-члены класса доступны для функции-членов этого класса и других функций программы, в которой имеется представитель класса.

В C++ класс, структура и объединение рассматриваются как типы классов. Структура и класс подобны друг другу, за исклю­чением доступа по умолчанию: в структуре элементы имеют по умолчанию доступ public, в то время как в классе - private. Объединение, как и структура, по умолчанию предоставляет дос­туп public.

В приведенной ниже таблице 2 перечислены эти отличия.

 

Таблица 2.

Различие между классом, структурой и объединением

 

Различие Классы Структуры Объединения
Ключевое слово: class struct union
Доступно умолчанию: private public public
Перекрытие данных: Нет Нет Да

Структуры и объединения могут иметь конструкторы и дест­рукторы. Вместе с тем имеется несколько ограничений на ис­пользование объединений в качестве классов. Во-первых, они не могут наследовать какой бы то ни было класс, и они сами не мо­гут использоваться в качестве базового класса для любого друго­го типа. Короче говоря, объединения не поддерживают иерархию классов. Объединения не могут иметь членов с атрибутом static. Они также не должны содержать объектов с конструк­тором и деструктором. Рассмотрим пример использования объе­динения в качестве класса:

#include <iostream.h>

union Bits

{

Bits(unsigned int n);

void ShowBits ();

unsigned int num;

unsigned char с[sizeof(unsigned int)];

};

Bits::Bits(unsigned int n)

{

num = n;

}

void

Bits:: ShowBits ()

{

int i, j;

for (j=sizeof(unsigned int)-1; j>=0; j—)

{ cout «"Двоичное представление байта "

<< j << ":"

for (i=128; i; i»=l)

{ if (i & c[j]) cout << "I";

else cout << "0";

}

cout << "\n";

}

}

 

int mainQ

{

Bits ob(2000); ob.ShowBits();

return 0;

}

В этом примере осуществляется побайтовый вывод переданного объекту беззнакового целочисленного значения в двоичном виде.

 

Конструкторы и деструкторы.

Список инициализации элементов

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

#indude <iostream.h>

class AnyClass

{

int var;

public:

AnyClass(); //Конструктор

void Show();

};

AnyClass:: AnyClass()

{

cout << “В конструкторе\п”;

var = 0;

}

void

AnyClass:: Show ()

{

cout << var;

}

int main ()

{

AnyClass ob;

ob.Show();

//...

return 0;

}

В этом примере конструктор класса AnyClass выводит со­общение на экран и инициализирует значение закрытой перемен­ной класса var.

Заметим, что программист не должен писать код, вызы­вающий конструктор класса. Всю необходимую работу выпол­няет компилятор. Конструктор вызывается тогда, когда созда­ется объект его класса. Объект, в свою очередь, создается при выполнении оператора, объявляющего этот объект. Таким образом, в C++ оператор объявления переменной является выполнимым оператором. Для глобальных объектов конструктор вызывается тогда, когда начинается выполнение программы. Для локальных объектов эр вызывается всякий раз при выполнении оператора, объявляющего переменную. Функцией-членом, выполняющей действия, обратные конструктору, является деструктор. Эта функция-член вызывается удалении объекта. Деструктор обычно выполняет работу по освобождению памяти, занятой объектом. Он имеет то же имя, и класс, которому он принадлежит, с предшествующим символом ~ и не имеет возвращаемого значения. Рассмотрим пример, содержащего деструктор:

#indude <iostream.h>

class AnyClass

{

int var;

public:

AnyClass(); // Конструктор

~AnyClass(); //Деструктор

void Show();

};

AnyClass:: AnyClass() {

cout << "Мы в конструкторе\п";

var = 0;

}

AnyClass::~ AnyClass()

{ cout «"Мы в деструкторе\п";}

void

AnyClass::Show()

{ cout << var << "\n";

}

int main()

{

AnyClass ob; ob.Show();

return 0;

Деструктор класса вызывается в момент удаления объекта. Это означает, что для глобальных объектов он вызывается при завершении программы, а для локальных - когда они выходят из области видимости. Заметим, что невозможно получить указате­ли на конструктор и деструктор.

Обычно конструктор содержит параметры, которые позво­ляют при построении объекта задать ему некоторые аргумен­ты. В рассмотренном выше примере конструктор инициализи­ровал закрытую переменную var класса AnyClass значени­ем 0. Если нужно проинициализировать переменные класса, используется конструктор с параметрами. Модифицируем предыдущий пример:

iinclude <iostream.h>

class AnyClass

{

int a, b; public:

//Конструктор с параметрами

AnyClass(int x, int y); //Деструктор

~AnyClass();void Show();

 

AnyClass:: AnyClass(int x, int y)

{

cout << “Мы в конструкторе\n";

a = x;

b=y;

AnyClass:: ~ AnyClass()

{ cout << "Мы в деструкторе\n";

 

void

AnyClass::Show()

{

cout << a << "\n";

}

 

int main()

{

AnyClass ob(3,7);

ob.Show();

//...

return 0;

}

Здесь значение, переданное в конструктор при объявлении объекта ob, используется для инициализации закрытых перемен­ных а и b этого объекта.

Фактически синтаксис передачи аргумента конструктору с па­раметрами является сокращенной формой записи следующего выражения:

AnyClass ob = AnyClass(3,7);

Однако практически всегда используется сокращенная форма синтаксиса, приведенная в примере.

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

Приведем правила, которые существуют для конструкторов:

· для конструктора не указывается тип возвращаемого зна­чения;

· конструктор не может возвращать значение;

· конструктор не наследуется;

· конструктор не может быть объявлен с модификатором
const, volatile, static или virtual.

Если в классе не определен конструктор, компилятор генерирует конструктор по умолчанию, не имеющий параметров.

Для деструкторов существуют следующие правила:

· деструктор не может иметь параметров;

· деструктор не может возвращать значение;

· деструктор не наследуется;

· класс не может иметь более одного деструктора;

· деструктор не может быть объявлен с модификатором

const, volatile, static или virtual.

Если в классе не определен деструктор, компилятор генериру­ет деструктор по умолчанию.

Подчеркнем еще раз: конструкторы и деструкторы в C++ вы­зываются автоматически, что гарантирует правильное создание и удаление объектов класса.

Не все приведенные выше правила станут вам ясны в данный момент.

Вернитесь к ним после прочтения нескольких последующих глав.

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

class AnyClass()

{

int a, b;

public:

AnyClass(int x, int y);

};

//Конструктор использует

//список инициализации

AnyClass::AnyClass(int x, int y): a(x), b(y)

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

Конструкторы по умолчанию и

конструкторы копирования

C++ определяет два специальных вида конструкторов: конструктор по умолчанию, о котором мы упоминали выше, и конструктор копирования. Конструктор по умолчанию не имеет параметров (или все его параметры должны иметь значения по умолчанию) и вызывается при создании объекта, которому не заданы аргументы. Следует избегать двусмысленности при вызове кон­структоров. В приведенном ниже примере два конструктора по молчанию являются двусмысленными:

class T

{

public:

//Конструктор по умолчанию

Т();

//Конструктор с одним параметром;
//может быть использован как конструктор
//по умолчанию
Т(int I=0);,

int main ()

{

Т obl(10); //Использует T::T(±nt)

Т ob2; //He верно; неоднозначность

//вызова. Т::Т() или T::T(lnt =0)

return 0;

}

|

 

В данном случае, чтобы устранить неоднозначность, достаточно удалить из

объявления класса конструктор по умолчанию.

Конструктор копирования (или конструктор копии) создает класса, копируя при этом данные из уже существующего i данного класса. В связи с этим он имеет в качестве един­ого параметра константную ссылку на объект класса

(const T&) или просто ссылку на объект класса (Т&). Использование первого предпочтительнее, так как последний не позволяет копировать константные объекты. Приведем пример использования конструктора копирования:

 

class Coord

{

int x, у;

public:

//Конструктор копирования

Coord(const Coord& src);

};

 

Coord::Coord(const Coord& src)

{

x = src.x;

у = src.у;

}

 

int main()

{

Coord ob1(2,9);

Coord ob2 = ob1;

Coord оbЗ(оb);

return 0;

}

 

Ссылка передается всякий раз, когда новый объект инициа­лизируется значениями существующего. Если вы не преду­смотрели конструктор копирования, компилятор генерирует конструктор копирования по умолчанию. В C++ различают поверхностное и глубинное копирование данных. При поверх­ностном копировании происходит передача только адреса от одной переменной к другой, в результате чего оба объекта ука­зывают на одни и те же ячейки памяти. В случае глубинного копирования происходит действительное копирование значе­ний всех переменных из одной области памяти в другую. Кон­структор копирования по умолчанию, созданный компилято­ром, создает буквальную (или побитную) копию объекта, то есть осуществляет поверхностное копирование. Полученная копия объекта скорее всего будет непригодной, если она со­держит указатели или ссылки. Действительно, если эти указа­тели или ссылки ссылаются на динамически распределенные объекты или на объекты, встроенные в копируемый объект, они будут недоступны в созданной копии объекта. Поэтому для классов, содержащих указатели и ссылки, следует вклю­чать в определение класса конструктор копирования, который будет осуществлять глубинное копирование, не полагаясь на создаваемый компилятором конструктор копирования по умолчанию. В этом конструкторе, как правило, выполняется звание динамических структур данных, на которые указатели на которые ссылаются члены класса. Класс должен содержать конструктор копирования, если он перегружает оператор присваивания.

Если в классе не определен конструктор, компилятор пытается сгенерировать собственный конструктор по умолчанию и, если нужно, собственный конструктор копирования. Эти сгенерированные компилятором конструкторы рассматриваются как открытые функции-члены. Подчеркнем, что компилятор генерирует эти конструкторы, если в классе не определен никакой другой конструктор.

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

Сгенерированный компилятором конструктор копирования -создает новый объект и выполняет почленное копирование содержимого исходного объекта. Если существуют конструкторы базового класса или члена-класса, — они вызываются; иначе выполняется побитное копирование. Если все базовые классы и классы членов-данных класса имеют конструкторы копирования, которые воспринимают const-аргумент, то сгенерированный ком­ам конструктор копирования воспринимает аргумент const T&. В противном случае он воспринимает аргумент Т& (без const).

Указатель this

Каждый объект в C++ содержит специальный указатель с именем this, который автоматически создается самим компилятором и указывает на данный объект. Типом this является Т*, где Т — тип класса данного объекта. Поскольку указатель this определёен в классе, область его действия — класс, в котором он определен. Фактически this является скрытым параметром класса, добавляемым самим компилятором к его определению. При вызове обычной функции-члена класса ей передается указа­тель this так, как если бы он был первым аргументом. Таким образом, вызов функции-члена

ObjName.FuncName(parl, par2);

компилятор трактует так:

ObjName.FuncName(&ObjName, parl, par2);

Но, поскольку аргументы помещаются в стек справа налево, указатель this помещается в него последним. В теле функции-члена адрес объекта доступен как указатель this. Дружествен­ным функциям и статическим функциям-членам класса (о них мы будем говорить позже) указатель this не передается. Нижесле­дующий пример демонстрирует использование этого указателя:

#include <iostream.h>

#include <string.h>

class T

{

public:

T(char*);

void Greeting();

char item[20];

}

T::T(char* name)

strcpy(item, name);

Greeting(); // Все три

this ->Greeting ().; // оператора

(*this).Greeting(); //эквивалентны

}

void

T:: Greeting ()

{

//Оба нижеследующих оператора эквивалентны

cout << "Hello, " << item << "\n";

cout << "Hello, " << this -> item << "\n";

}

int main()

{

T ob("dear.");

return 0;

}

Как можно видеть, внутри конструктора класса и функции-члена Greeting () обращения к данным-членам- класса и функ­циям-членам могут осуществляться как непосредственно по имени, так и с помощью указателя this. Поэтому на практике такое употребление указателя this встречается крайне редко. В основном указатель this используется для возврата указателя (в форме: return this;) или ссылки (в форме: return;*this;) на соответствующий объект. Этот указатель находит широкое применение при перегрузке операторов.

Встраиваемые (inline-) функции

В C++ можно задать функцию, которая, фактически, не вызывается, а ее тело встраивается в программу в месте ее вызова. Она действует почти так же, как макроопределение с параметрами. По сравнению с обычными функциями встраиваемые (in-line) функ­ции обладают тем преимуществом, что их вызов не связан с передачей аргументов и возвратом результатов через стек и, следовательно, они выполняются быстрее обычных. Недостатком встраиваемых функций является то, что если они слишком большие и вызываются слишком часто, объем программы сильно возрастает. Из-за этого применение встраиваемых функций обычно ограничивается только очень простыми функциями.

Объявление встраиваемой функции осуществляется с помощью спецификатора inline, который вписывается перед опре­делением функции.

Следует иметь в виду, что спецификатор inline только формулирует требование компилятору сформировать встроенную э. Если компилятор не в состоянии выполнить это требование, функция компилируется как обычная. Компилятор не может сгенерировать функцию как встраиваемую, если она:

· содержит оператор цикла (for, while, do-while);

· содержит оператор switch или goto;

 

 

Классы ObjectWindows

OWL содержит множество классов, способствующих более быстрому и простому написанию прикладных программ. OWL-классы представляют набор объектов, из которых создается Windows-приложение таких объек­тов, как окна, диалоговые окна, меню, элементы управления и другие, включая некоторые специальные объекты, такие как строки состояния и управления.

В частности, ObjectWindows 2.0 поддерживает следующие основные категории классов:

· Приложения (Applications)

· Окна (Windows)

· Меню (Menus)

· Окна диалога (Dialog boxes)

· Элементы управления (Controls)

· Графика (Graphics)

· Печать (Printing)

· Контроль ввода (Validators)

· Просмотр документов (Document and views)

· Буфер обмена (Clipboard)

 

Класс TApplication

Любая программа, написанная с использованием ObjectWindows, начинает свое существование, как объект приложения. Этот объект порождается классом TApplication библиотеки OWL и обеспечивает инициализацию, выполнение и завершение вашей Windows-программы. Более конкретно: TApplication регистрирует, создает и отображает основное окно приложения; поддерживает работу цикла обработки сообщений (таким образом, что прикладная программа может взаимодействовать как с пользователем, так и с Windows), и закрывает его, когда работа за­кончена.

Класс TApplication обеспечивает полноценную работающую Windows-программу, выполняющую, правда, не более сложное действие, чем вывод окна на экран. TApplication поддерживает некоторые дополнительные функции - такие, как обеспечение доступа к командной строке приложе­ния, позволяя подключать либо библиотеку настраиваемых элементов управления Borland, либо библиотеку 3-мерных элементов управления Microsoft, а также определить, когда Windows простаивает.

 

Оконные классы

Когда создаётся базовое OWL-приложение, TApplication автома­тически создает главное окно. Это окно полностью функционирует, то есть можно изменить его размеры, переместить, максимизировать, ми­нимизировать и закрыть.

Оконные OWL-классы, позволяют на­растить функциональные возможности вашего окна по сравнению со стандартными. Чтобы облегчить эту задачу, OWL вводит несколько раз­личных видов окон, а именно:

· Дочерние окна общего вида

· Родительские окна

· Декорированные обрамляющие окна

· MDI-окна

Каждый из этих типов обсуждается в следующих разделах.

Дочерние окна общего вида

Дочернее окно общего вида представлено в OWL 2.0 классом TWindow. Это основное окно, которое обеспечивает поддержку меню, линейки про­крутки, элементы управления, оконную графику, обмен данными, стан­дартную обработку сообщений и многое другое.

Хотя класс TWindow можно использовать для создания основного ок­на, его все же лучше попридержать для других целей. Основное окно приложения должно быть окном класса TFrameWindow, который описан в следующем разделе.

Родительские окна

Родительские окна, представленные классом TFrameWindow, поддержи­вают все функции класса TWindow и, вдобавок, работу с клавиатурой и окнами пользователя. Родительские окна являются также базовым классом для декорированных MDI-окон. Большинство функций TFrameWindow наследуется из базового класса TWindow, представляюще­го общие окна в ObjectWindows 1.0 и ObjectWindows 2.0, главное окно представлено классом TFrameWindow. Фактически, окно, создаваемое объектом TApplication по умолчанию, является обрамляющим.

 

Декорированные обрамляющие окна

Декорированные обрамляющие окна, инкапсулированные в классе TDecoratedFrame и производные от обычных обрамляющих окон и макет­ных (layout) окон, позволяют вставить в приложение такие элементы оформления, как панели инструментов, строки подсказки и состояния, инструментарии, представленные соответственно классами TControlBar, TToolBox, TMessageBar и TStatusBar.

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

MDI-окна

Для обеспечения многодокументного интерфейса (MDI) ObjectWindows поддерживает несколько оконных классов, служащих специально для создания MDI-приложений. Родительское MDI-okho, включенное в класс TMDIFrame, работает как основное окно MDI-приложения. Во время работы такой программы это окно содержит, как минимум, невидимое окно пользователя и, возможно, несколько до­черних окон. Родительское окно обрабатывает основное меню прило­жения, включающее специальное меню Windows. Это меню позволя­ет выбирать окна и размещать их по принципу cascade, tile, либо произвольно.

MDI-окно пользователя, представленное классом TMDIClient, поддер­живает большинство функций MDI-приложений. Вообще говоря, сооб­щения, посылаемые MDI-приложению, направляются для обработки в
окно пользователя. Окно пользователя автоматически обрабатывает четыре основные команды оконного меню MDI-программы, позволяя без
особых усилий добавить новые окна по способу cascade или tile, а также
закрывать их. МТI-окно-клиент может также автоматически создавать
дочерние MDI-окна. '

Все дочерние окна в MDI-приложений должны быть дочерними MDI-окнами, поэтому для окон такого типа ObjectWindows, само собой, под­держивает специальный класс TMDIChild. Дочерние MDI-окна работают почти так же, как и родительские окна на главной панели Windows, только здесь «рабочий стол» (desktop) определяется окном-клиентом MDI-приложения. Пользователь может свернуть дочерние MDI-окна до иконки или максимизировать их, заполняя все окно-клиент.

 

Меню

Одной из отличительных черт Windows-программы является строка меню. Почти все приложения Windows используют меню, что подразу­мевает (или должно подразумевать) определенные правила их построе­ния. Следуя этим правилам, пользователь отыскивает известные ему ко­манды в ожидаемом месте независимо от того, какое приложение активно в данный момент. Для обработки простого меню отлично рабо­тают обычные методы, для более гибкой работы с меню используются OWL-классы TMenu, TSystemMenu и TPopupMenu.

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

Класс TSystemMenu предлагает дополнительные функции управления системным меню. Этот класс позволяет заменить системное меню окна на свое собственное. Наконец, класс TPopupMenu позволяет создавать в любом месте окна всплывающее меню.

Окна диалога

Аналогично тому, как большинство Windows-приложений использует меню для получения от пользователя команд, окна диалога используются для ввода данных. Для окон диалога в OWL существует класс TDialog, по­добный классу TMenu. Класс TDialog выполняет всю работу, связанную с созданием, функционированием и закрытием окна диалога, включая встроенную обработку наиболее часто используемых типов кнопок и ме­ханизмы пересылки данных в и из окна диалога. Кроме того, окно может быть модальным и немодальным, может содержать множество элементов управления и может даже изображаться как 3-мерная пространственная форма с помощью библиотек DLL фирм Borland и Microsoft.

OWL также инкапсулирует в классы стандартные диалоговые окна
Windows и другие «сборные» диалоговые окна. Эти классы, включая
TInputDialog, TPrinterAbortDlg, TChooseColorDialog,

TFindReplaceDialog, TChooseFonDialog, TPrintDialog и

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

 

 

Элементы управления

Приложения Windows загружаются вместе со специальными элемен­тами управления, такими, как кнопки, окна списков, линейки прокрут­ки и окна редактирования.

Поскольку в приложениях интенсивно используются элементы управления Windows, они реализованы в OWL в качестве классов. На­пример, элемент «окно списка», включенный в класс TListBox, содер­жит функции-члены для вставки и удаления строк списка, очистки списка, поиска в нем заданной строки, определения числа выбранных элементов списка, восстановления выбранных строк, пометки строк и другие. Класс TScrollBar, реализующий линейки прокрутки, позволя­ет, в частности, получить и задать позицию бегунка, задать диапазон прокрутки.

Кроме перечисленных выше классов, в OWL существуют классы для кно-пк (TButton), групповых окон (TGroupBox), комбинированных окон (TCornboBox), элементов управления редактированием (TEdit), окон переключателей (TCheckBox), радио-кнопок (TRadioButton) и управления статическим текстом (TStatic). OWL поддерживает также применяемые в приложениях классы управления настройкой. К примеру, элемент, представ­ленный классом TGauge, отображает вертикальную и горизонтальную шка­лы, показывающие, насколько процесс близок к завершению. Вертикальная и горизонтальная шкалы, включенные в классы THSlider и TVSlider, позво­ляют выбрать величину из заданного диапазона.

 

Графика

Поскольку Windows представляет собой графический интерфейс пользо­вателя (GUI), приложения в большей степени зависят от предоставляемых Windows графических средств. Эти средства и составляют графический ап­паратный интерфейс (GDI) Windows. С целью сделать функции GDI более доступными, в ObjectWindows реализованы десять специальных классов. Сюда входят классы контекстов устройств (TDS), кисти (ТРеn), пиктограм­мы (иконки) (ТТсоn), растровые изображения (TBitmap), курсоры (TCursor), шрифты (TFont), палитры (TPalette), аппаратно-независимые растровые изображения (TDib) и области (TRegion).

Класс TDC является основным классом для других специальных клас­сов контекстов устройств (DC). Этот класс содержит большинство GDI-функций Windows — таких, как рисование форм, отображение текста, кнопок и растровых изображений, задание режима рисования, выбор и восстановление объектов GDI, задание цвета и другие. Специальные классы DC включают контексты окна (TWindowDC), закраски (TPainfcDC), метафайла (TMetafileDC), памяти (TMemoryDC) и принтера (TPrintDC). Каждый класс DC включает множество функций, осуществдяющих вызов стандартных, относящихся к данному контексту устрой­ства (DC) функций Windows. Например, класс TPrintDC поддерживает функции запуска и остановки принтера, инициализации и завершения страницы, задания числа копий, снятия документа и другие.

 

В Windows-приложении вывод на экран гораздо более сложен, чем в програм­мах, работающих под DOS. Для вывода на экран в Windows-приложении необ­ходимо вначале получить контекст устройства (DC) для окна, в которое выво­дится информация. DC — это структура данных, содержащая разного рода графические установки для данного устройства, включая перо, кисть, типы ли­ний, а также информация о цвете и форме отображения. Хотя чаще всего уст­ройством является окно на экране, контекст требуется и для таких устройств, как принтер.

Печать

Аппаратная независимость Windows, поддерживаемая большим ко­личеством возможных драйверов, приводит к тому, что вывод на прин­тер в Windows — задача непростая. Но теперь, благодаря новым клас­сам OWL, вы можете напечатать документ любого типа, приложив при этом минимум усилий. В частности, для управления заданиями для принтера OWL поддерживает два класса: класс TPrinter, включающий функции принтера и поддержку драйверов, и класс TPrintout, от­вечающий за подготовку документа к печати. Оба эти класса вместе служат для получения твердых копий с помощью установленного в данный момент принтера.

Когда вы создаете объект, относящийся к классу TPrinter, приложе­ние автоматически связывается с принтером пользователя, заданным по умолчанию так, как указано в файле WIN.INI. Объект TPrintout, будучи весьма мощным средством, позволяет также легко напечатать простой, в одну страницу, документ с помощью одной-единственной функции, как и осуществить вывод в область окна с помощью оконной функции закрас­ки. Для более сложных многостраничных документов TPrintout помога­ет произвести разбивку на страницы, компоновку, управлять размером страниц и взаимодействовать с пользователем через специальное окно диалога.

 

Компоновка — это стандартный метод печати документов в Windows. Он за­ключается в разбиении документа на серию горизонтальных прямоугольников, называемых группами (bands).

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

 

 

Контроль ввода

Другой громоздкой функцией при написании Windows-программ являет­ся контроль содержимого окон диалога после ввода данных пользователем. До появления ObjectWindows 2.0 вам приходилось самому писать функции контроля данных, которые вызывались до закрытия окна. Теперь OWL про­делывает все это с помощью объектов. Пять специальных классов, осущест­вляющих контроль, а именно: TFilterValidator, TRangeValidator, TLookupValidator, TStringLookupValidator и TPXPictureValidator — по­зволяют проверять вводимые данные на допустимые символы, диапазон, идентифицировать принадлежность элемента к таблице допустимых ответов и применять шаблон при вводе.

Для использования объекта-контролера необходимо лишь создать этот объект и связать его с нужной строкой редактирования. Эта строка осуществляет затем автоматический доступ к контролеру, выполняя проверку без малейшего участия а вашей стороны. Разумеется, вы може­те написать свои собственные настраиваемые классы контроля данных, перекрывая функции базового класса TValidator.

 

Просмотр документов

Большинство Windows-приложений имеет дело с обработкой документов того или иного вида. Текстовые процессоры работают с текстовыми файла­ми, графические редакторы — с изображениями, генераторы звуковых эф­фектов — со звуковыми файлами. В некоторых случаях приложение долж­но уметь обработать документ несколькими способами. Например,

редактор файлов может обрабатывать как текстовые ASCII-файлы, так и двоичные данные, выводимые на экран в двоичном или шестнадцатирич­ном формате. Чтобы помочь вести обработку документов, OWL предлагает модель Doc/View, включающую объект документа, объект просмотра и об­работчик документа.

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

Объект просмотра, относящийся к классу TView, представляет собой функциональную црослойку между документом и интерфейсной частью, используемой для его обработки (например, окном или диалоговым ок­ном). Просмотр позволяет отображать данные различными способами и дает пользователю возможность их обрабатывать. Чтобы извлечь из просмотра дополнительную пользу, вы должны переписать ряд вирту­альных функций класса, заставляя их работать так, как требуется для данного типа просмотра. Один документ может быть связан с несколь­кими различными объектами просмотра.

Буфер обмена

Одним из многих преимуществ Windows является возможность обме­на данными между приложениями. Наиболее распространенным меха­низмом такой передачи является буфер обмена (Clipboard). Данные мо­гут быть вырезаны или скопированы в буфер обмена одного приложения, а затем переданы оттуда в документ другого приложения.

Поскольку буфер обмена регулярно используется в Windows-програм­мах, в OWL существует класс TClipboard, вобравший в себя множество функций Windows для работы с буфером обмена. Используя TClipboard, вы можете открыть и закрыть буфер, очистить его, проверить формат дан­ных, хранящихся в нем, копировать в него и извлекать из него данные, а также выполнить любую из других 14 функций работы с буфером обмена.

OWL включает также специальный класс TClipboardViewer, который автоматически добавляется и удаляется из цепочки Windows, осуществ­ляющей просмотр буфера обмена. Этот класс поддерживает также отве­ты на сообщения, генерируемые Windows^для просмотра буфера обмена.

Создание объекта приложения

Пример 1. TINIEST.CPP — простейшее OWL-приложение.

 

#include <owl\applicat.h>

int OwlMain(int, char*[])

{

TApplication App('Tinest App");

return app.Run();

}

В примере 1 приведено самое короткое возможное OWL-приложение. Как видно, оно состоит всего из семи строк, включая пустую строку, от­крывающую и закрывающую фигурные скобки. При более тщательном подходе к программе можно уложиться и в меньшее число строк. Когда программа будет откомпилирована и запущена, на экране появится окно, показанное на рис. 1. Это полноценное окно с системным меню и всеми элементами управления, необходимыми для перемещения окна, из­менения его размеров, минимизации и максимизации.


 

Рис. 1. Простейшее приложение

Первая строка программы 1 включает в OWL-приложение заголовочный файл для объекта приложения OWL. Для большинства OWL-объектов заголовочный файл содержится в каталоге BC4\INCLUDE\OWL. Чтобы получить доступ к OWL-объекту, необходимо включить его заголовочный файл в про­грамму. В примере 1 используется только один OWL-объект — объ­ект приложения, поэтому в начале примера подключается только один заголовочный файл.

Следующая строка (после пустой) является первой строкой функции OwlMain(), с которой начинается работа любой OWL-программы. Поми­мо того, что отпадает нужда в сложной функции WinMainO, OwLMain() обеспечивает доступ к аргументам командной строки argc и argv (кото­рые не используются в примере 1).

Внутри функции OwlMain () вы выделяете из базового OWL-класса TApplication объект вашей программы. Класс TApplication имеет два конструктора. Первый (который как раз и используется в программе 1) имеет единственный аргумент — имя приложения, которое появляется в строке заголовка основного окна. Прототип этого конструктора выглядит следующим образом:

TApplication (const char far *name = 0);

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

 

 

Внимание! В приложениях, написанных с помощью ObjectWindows 1.0, выполнение про­граммы начинается с вызова функции WinMain (), как и в большинстве Windows-программ. В ObjectWindows 2.0 же выполнение программы начинает­ся с обращения к функции OwlMain(). Это связано тем, что в OWL предусмот­рена своя версия функции WinMain(), которая обеспечивает собственную проверку и обработку ошибок. Эта принятая по умолчанию версия автоматически вызывает функцию OwдMain(). И хотя можно написать свою собственную WinMain (), в этом нет никакой необходимости.  

 

Другой конструктор TApplication, который следует использовать лишь при необходимости написать собственную версию WinMain () (это бывает, хотя и не чаще, чем вы ходите по потолку), поддерживает дос­туп к аргументам, используемым функцией WinMain (). Этот конструк­тор приведен ниже:

TApplication (const char far *name,

HINSTANCE instance, HINSTANCE prevlnstance,

const char far *cmdLine, int cmdShow);

 

Функция WinMain () из примера 1 вначале генерирует объект - приложение под названием Арр. В следующей строке вы вызываете функцию-член Run () объекта Арр, которая переводит приложение в активное и состояние, инициализирует его и запускает цикл обработки сообщений.

Run() заканчивает работу только тогда, когда пользователь закрывает приложение.

Понятие об основном окне приложения

Хотя простейшая OWL-программа из примера 2.1 создает полноценное; работающее основное окно, оно не способно взаимодействовать с пользо-' вателем, кроме как через элементы управления, и может только переме­щаться, менять размер, сворачиваться и разворачиваться. Такое прило­жение не только скучно, как соревнование по стрижке газона, — оно также по большому счету бесполезно, разумеется, если только целью не является демонстрация работы основных элементов управления окном.

Чтобы сделать OWL-приложение полезным, нужно заставить объект приложения создать окно более сложное, чем то, которое создается по умолчанию. Для этого необходимо переписать виртуальную функцию InitMainWindow() класса TApplication, как показано в примере 2.

Пример2. TINYAPP.CPP — программа, задающая регулируемое основное окно.

/////////////////////////////////////////////////// TINYAPP2.СРР: /////////////////////////////////////////////////

// Демонстрирует создание,класса

// приложения и задание класса его основного окна

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

<== предыдущая лекция | следующая лекция ==>
Формат 2 | Краткий справочник по Си
Поделиться с друзьями:


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


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



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




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