Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка по программированию.doc
Скачиваний:
11
Добавлен:
13.11.2019
Размер:
1.2 Mб
Скачать

Void main()

{

printf(abs(-2);

}

Прежде всего, можно убедиться в том, что компиляция программы выдаст ошибку, связанную с тем, что обнаруживается конфликт с уже существующей стандартной функцией abs. Дело в том, что мы пытаемся просто переписать функцию того же имени и того же типа, что и стандартная. Если заменить имя, например, на rabs, то все пройдет нормально, и программа выполнит необходимое действие. Однако мы хотим другого. Мы хотим, чтобы функция abs находила модуль как целого, так и вещественного числа. Для этого определение функции представим в виде:

float abs(float x)

{

float y;

if(x<0) y=-x; else y=x;

return y;

}

В вызывающей функции можно, например, написать выражение:

printf(abs(-2.3));

Таким образом, мы выполнили перегрузку функции abs на тип float. Аналогичную процедуру можно было бы проделать и для типов double и long.

Безотносительно темы данного раздела укажем, что тело функции abs хотя и записано правильно, но несколько громоздко и не лучшим образом. Более грамотно было бы использовать ранее нами не рассмотренную конструкцию языка С вида:

Условие ? Выражение1: Выражение2;

Эта конструкция работает следующим образом. Если Условие имеет значение, не равное нулю (ИСТИНА), то конструкция возвращает значение Выражения1, в противном случае – значение Выражения2. Тогда определение функции можно записать, в частности, так:

long abs(long x)

{

return x<0 ? –x: x;

}

Можно видеть, что запись тела функции выглядит гораздо компактнее. Кроме того, в такой форме нам уже не требуется локальная переменная y.

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

Наряду с перегрузкой функций в С++ широко используется и перегрузка операторов. Под термином оператор в языке понимается очень многое. Знак операции сложения + является бинарным оператором, слева и справа от которого находятся операнды – слагаемые. Два знака ++ также являются оператором для унарной операции инкремента. Не столь очевидным является, например тот факт, что пара прямых скобок [ ] также является оператором индексирования, то есть оператором присвоения номера объекту. Очевидно, перегрузка операторов позволяет использовать один и тот же символ для сходных дествий над объектами различных типов. Большинство операторов в С++ могут быть перегружены, однако, в силу большого разнообразия операторов мы остановимся только на перегрузке простейших бинарных операций.

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

Тип Имя_класса::operator#(Аргументы)

{

//Исполняемые инструкции;

}

Здесь Тип – тип возвращаемого функцией значения. В большинстве случаев это будет тип класса, для которого делается перегрузка, но не обязательно. Далеe указывается имя класса и, после разделителя :: пишется служебное слово operator. Вместо символа # как раз и следует указать перегружаемый оператор, как то +, --, * и так далее.

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

Все сказанное, наверное, воспринимается пока слишком абстрактно. Что же, попробуем продемонстрировать ситуацию примером. Создадим «самодельный» класс комплексных чисел и перегрузим для него некоторые арифметические операции. Обратимся к тексту заголовочного файла с описанием класса.

class COMP

{

public:

double a,b;

COMP(double, double) ;

COMP() ;

COMP operator+(COMP);

COMP operator-(COMP);

COMP operator*(COMP);

};

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

Реализация представлена в следующем фрагменте.

COMP::COMP(double aa, double bb)

{a=aa; b=bb;}

COMP::COMP()

{a=0.0; b=0.0;}

COMP COMP::operator+(COMP r)

{

COMP tmp;

tmp.a = a+r.a; tmp.b = b+r.b;

return tmp;

}

COMP COMP::operator-(COMP r)

{

COMP tmp;

tmp.a = a-r.a; tmp.b = b-r.b;

return tmp;

}

COMP COMP::operator*(COMP r)

{

COMP tmp;

tmp.a = a*r.a-b*r.b; tmp.b = a*r.b+b*r.a;

return tmp;

}

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

Перегрузку рассмотрим на примере операции сложения. Как известно, при сложении двух комплексных чисел складываются их вещественные и мнимые части. Внутри тела функции-оператора организуется локальная переменная tmp – комплексное число. Следующие два присваивания добавляют к левому операнду – первому слагаемому правый операнд – второе слагаемое. Результат остается в промежуточной переменной и возвращается инструкцией return. Аналогично перегружается оператор вычитания и, в соответствии с правилом умножения комплексных чисел, - оператор произведения.

Теперь нам осталось взглянуть на вызывающую наш пример часть программы:

{

COMP z1(1.1,2.2),z2(-1.0,-2.0),z3,z5;

COMP *z4 = new COMP();

*z4 = z1+z2;

z3 = z1-z2;

z5 = z1*z2;

printf(“%lf\n”,z4->b);

printf(“%lf\n”,z3.b);

printf(“%lf”,z5.a);

}

Здесь стандартным образом с использованием конструкторов с параметрами создаются два комплексных числа z1 и z2. С помощью конструкторов без параметров создаются числа z3 и z5. Комплексное число z4 объявляется через указатель с использованием оператора new. Далее демонстрируется выполнение сложения, вычитания и умножения с перегруженными на комплексные числа операторами. Результаты выводятся на экран.

Приложения с графическим интерфейсом

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

Для начала мы еще раз, несколько подробнее, рассмотрим технику работы с Builder’ом, и сделаем это на нескольких типичных примерах. В соответствии с традициями обучения работе с новыми для пользователя системами программирования поставим себе задачу разработать приложение, которое всего лишь выводит на экран приветствие при своем запуске.

Прежде всего, создадим с помощью проводника Windows или любого файлового менеджера специальную папку для хранения проекта приложения. Пусть это будет каталог NewFold в корневом директории диска С. То есть DOS’овский путь к паке выглядит как C:\NewFold. Теперь запускаем Builder и попадаем в его стартовое окно, изображенное на рисунке.

По умолчанию программа открывается в состоянии, готовом к разработке 32-разрядного Windows-приложения, с чем мы и согласимся. Давайте для начала сохраним наш пока пустой проект в подготовленной папке. Для этого из пункта меню File нужно взвыть подпункт Save all или воспользоваться комбинацией клавиш Ctrl+Shift+S. Откроется окно перемещений по файловой системе, где вы должны войти в нашу папку NewFold и нажать кнопку Сохранить. Тем самым будет создан и сохранен файл главного текстового модуля с именем Unit1.cpp. мя конечно можно и изменить, но мы оставим предлагаемое по умолчанию. Затем здесь же будет предложено создать и сохранить файл проекта Project1.bpr. Давайте и с этим согласимся. Теперь, если вы заглянете в папку проекта, вы обнаружите там готовый, но пока пустой проект, состоящий из нескольких файлов-заготовок. Самое главное то, что теперь можно закрыть Builder и назавтра или через год снова начать работу с проектом. Давайте закроем и снова откроем программу. Вызвать проект можно через пункт меню File - подпункт Open Project (Ctrl+F11), перейдя далее в папку проекта и открыв тот самый файл проекта Project1.bpr. Можно поступить и по-другому. Откройте пункт File, подпункт Reopen. Здесь вы увидите ссылку на нужный файл и, возможно, на другие недавно используемые файлы.

Итак, проект загружен. Давайте посмотрим, что система успела сделать автоматически без вашего участия. В папке проекта образовано несколько файлов, среди которых для нас интересен главный текстовый модуль Unit1.cpp. Для того, чтобы посмотреть содержимое этого файла можно открыть его окно. Оно находится под окном формы Form1 на представленном выше рисунке. Щелкните мышью по области, частично скрытой формой, то есть в зоне, где написано Insert. Откроется листинг, представленный далее.

#include <vcl.h>

#pragma hdrstop

#include "Unit1.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

Пока здесь практически ничего нет. Правда, мы уже понимаем, что к основному модулю подключаются два заголовка vcl.h и Unit1.h. Строка TForm1 *Form1; означает, что создается указатель Form1 на некий класс. Это - класс так называемой формы. Форма представляет собой специальный графический элемент Windows, который будет открываться при запуске изготовленного приложения. В рабочем окне формы можно размещать различные управляющие элементы, выводить результаты расчетов, рисовать графики и делать многое другое. Пока же в нашей форме вообще ничего нет, и соответствующее окно будет иметь только стандартный инструмент закрытия - крестик в правом верхнем углу.

Хотя мы называем проект пустым, из него можно изготовить приложение, которое можно запустить на исполнение и которое, естественно ничего делать не будет. Выберите пункт меню Run и подпункт с тем же названием, или просто нажмите функциональную клавишу F9 на клавиатуре. Система выполнит компиляцию программы, редактирование связей (линковку) и запустит приложение. С открывшимся окном программы можно сделать только одно – закрыть его. Ведь наша первая программа ничего делать не умеет. Если вы заглянете в папку проекта, то обнаружите там новые файлы, в частности, исполняемый файл программы Project1.exe. Это и есть наша программа, которую можно запускать уже и без Builder’а и даже на другом компьютере.

Теперь пойдем дальше и разместим на форме управляющую кнопку. Для начала сделайте так, чтобы активным стало окно формы, например, свернув окно текстового модуля. Нам понадобится обратиться к панели так называемых визуальных компонентов. Эта панель (см. рисунок) имеет множество вкладок, среди которых по умолчанию открыта вкладка Standard. Она-то нам и нужна. Найдите на вкладке маленькую картинку, изображающую кнопку с названием ОК, сделайте по ней щелчок левой кнопкой мыши, переведите мышиный курсор в любое место рабочего поля формы и снова сделайте щелчок мышью. В результате на форме появится кнопка с именем Button1. Сделайте по ней двойной щелчок, и вы снова попадете в окно Unit1.cpp. Вы обнаружите, что к предыдущему тексту добавлена конструкция: