БГУ Пособие - Программирование в C++ Builder. Учебное пособие по курсу методы программирования для студентов специальностей
Скачать 1.24 Mb.
|
Пример. #include #include 48 cout<<”str3: “< 49 // Выводится p= 2 p=str1.find(str3,3); cout<<”p= “< // Выводится p= 13 p=str1.find(‘A’); cout<<”p= “< // Выводится p= 2 p=str1.find(“CDE”); cout<<”p= “< // Выводится p= 4 p=str1.rfind(str3); cout<<”p= “< // Выводится p= 13 p=str1.rfind(‘A’); cout<<”p= “< // Выводится p= 13 p=str1.rfind(“AB”); cout<<”p= “< // Выводится p= 13 str2=str3.substr(2,4); cout<<”str2: “< } Следующий пример также иллюстрирует применение класса string в C++Builder. Строка отображается в компонентах типа строки редактиро- вания Edit1 и Edit2. Процедура запускается кнопкой Button1. #include #include // Обработчик события, возникающего при нажатии // кнопки "Show" void __fastcall TForm1::ButtonlClick(TObject *Sender) { // Создание экземпляра класса string string str; str = "C++ "; str += "is the best.."; Edit1->Text = str.c_str();// Преобразование к C-строке // Объявление символьного массива языка С char buff[30]; strcpy(buff, "Builder C++ "); strcat(buff, "is the best too."); int len = strlen(buff); Edit2->Text = buff; if (len >= 30) 50 ShowMessage("Переполнение буфера!!!"); } Метод c_str () возвращает указатель на символьный массив, содер- жащий копию строки из объекта str. Попытка присваивания значения объекта str свойству Text объекта Edit2 выдала бы ошибку компиляции. Отметим, что при создании экземпляра str не пришлось указывать пре- дельный размер строки. Класс string динамически отводит дополнитель- ную память при необходимости. В следующем примере для выбора файла открывается диалоговое ок- но класса TOpenDialog при нажатии кнопки Button2. Имя файла отобра- жаетсяся в объекте Memo1 главной формы Form1. Имя файла затем ис- пользуется для открытия выбранного файла, ввода строки и ее вывода в объект Memo1. #include #include { Caption = OpenDialog1->FileName; // полный путь и имя файла str = OpenDialog1->FileName.c_str(); } str1=str; str.insert(0,"Имя файла: ") ; Memo1->Lines->Add(str.c_str()); // Вывести в Memo1 путь и имя файла ifstream in(str1.c_str()); in>>buf; Memo1->Lines->Add(buf); // Вывести в Memo1 введенную строку } Класс String из библиотеки VCL. При работе с компонентами VCL часто встречается тип AnsiString для описания строк произвольной дли- ны. Из-за того, что название AnsiString не кажется привлекательным, пользователям C++Builder рекомендуется его синоним – класс String (на- звание начинается с заглавной буквы) Действительно, в файле sysdefs.h, который автоматически включается в заголовки разрабатываемых при- ложений, можно найти определение тождественности типов typedef AnsiString String; Конструкторы класса String позволяют создавать строчные объекты из переменных типа char*, int или даже double. Например: String str = "Текстовая строка"; 51 Класс String имеет ряд переопределенных операторов присваивания (=), конкатенации (+), сравнения, характерных для строчных классов во- обще. При сравнении разнотипных объектов неявное преобразование ти- па выполняется автоматически: char* buff = "Текстовая строка"; String str = "Текстовая строка"; if (str == buff) {…} // если строки одинаковые Класс String инкапсулирует набор методов, которые позволяют реа- лизовать операции над строками. Наиболее часто используются следую- щие методы: c_str() – возвращает указатель char* на С-строку, содержащую копию исходной строки. Length() – возвращает длину строки (число символов в строке). IsEmpty() – возвращает значение true, если длина строки равна нулю. Insert() – вставляет текст в указанную позицию строки. Delete() – удаляет заданное число символов из строки. Pos() – возвращает индекс начала заданной комбинации символов в строке. LastDelimiter() – возвращает индекс последнего вхождения в строку заданного символа-ограничителя. LowerCase() – возвращает измененную исходную строку, символы которой заменяются строчными буквами (приводятся к нижнему регист- ру). UpperCase() – возвращает измененную исходную строку, символы которой приводятся к верхнему регистру. Trim() – возвращает измененную исходную строку, в которой удале- ны управляющие символы, а также пробелы в начале и конце строки. Format() – форматирование строки похожее на работу функции sprintf(). ТоInt() – преобразование строки в целое число. ТоDouble() – преобразование строки в число с плавающей точкой. SubString() – создает строку, равную некоторой подстроке исходной строки. Существуют два способа преобразования цифровых строк, вводимых в окна редактирования, в числа: String str; str = Editl->Text; int vail = atoi(str.c_str()); // с помощью функции atoi() int val2 = str.ToInt(); // с помощью метода ToInt() Отметим особенность класса String: символы строки индексируются начиная с 1 (как в Паскале), а не с 0 (как в C++). 52 Пример. Создается приложение, позволяющее выполнять сложение двух чисел. Будем использовать компоненты TEdit, TLabel и TButton. Используемые свойства и методы: TEdit: Name (имя объекта), ReadOnly (режим "только чтение"), Text (строка типа String), GetTextLen (длина строки), GetTextBuf (преобразо- вание свойства Text в С-строку). Используемые свойства и события компонента TButton: Caption (над- пись на кнопке), OnClick (событие, действия проводимые при нажатии на кнопку). Используемое свойство компонента TLabel: Caption (надпись). Ниже приводится обработчик события нажатия на кнопку: //Unit1.cpp: ------------------------------------------------------ void __fastcall TForm1::Button1Click(TObject *Sender){ int Size = Edit1->GetTextLen() + 1; char *Buffer = new char[Size]; Edit1->GetTextBuf(Buffer,Size); for(int i = 0; i < Size-1; i++) if(!isdigit(Buffer[i])&&Buffer[i]!='.') { Application->MessageBox("Вводите только цифры и точку", "Ошибка!", MB_OK); Edit1 -> Text = “”; return; } double n = atof(Buffer); delete[] Buffer; // Выбрасывается исключение, если в Edit2 введено не число try { double m; m= Edit2->Text.ToDouble(); Edit3->Text = n+m; } catch (...){ Application->MessageBox("Ошибка при вводе второго числа", "Ошибка!", MB_OK); Edit2 -> Text = “”; return; } } На рис. 15 показана форма приложения в процессе выполнения. 53 Рис. 15. Результат запуска приложения Работа со строками в текстовых компонентах. Компонент TLabel позволяет создать надпись: Label1->Font->Color=clRed; Label1->Caption=“Это красная метка”; Компонент TEdit представляет собой окно для ввода/вывода строки: Edit2->Text=Edit1->Text; Компонент TMemo используется для ввода и вывода нескольких строк: Memo1->Lines->Strings[i]; // доступ к i-й строке Свойство Lines содержит ряд методов: Add(), Append() – добавить новую строку; Delete(n) – удалить строку с номером n; SaveToFile(“имя файла”) – сохранить в файле, LoadFromFile(“имя файла”) – загрузить из файла. Например: Memo1->Lines->Add(Edit1->Text); Списки – являются производными от двух основных классов: TStringList – строчный список, TList – список объектов общего назначе- ния. Для отображения списков используются компоненты TListBox, TComboBox и другие. Компонент TListBox – список строк с линейной прокруткой. Пример. void __fastcall TForm1::Button1Click(TObject *Sender) { TStringList *MyList=new TStringList; ListBoxl->Clear(); // очистить список ListBox1->Items->Add("Первый элемент"); // Свойство Items содержит метод Add() и другие методы MyList->Add(ListBox1->Items[ListBox1->ItemIndex+1].GetText()); MyList->Add("Последняя строка"); ListBox1->Items->AddStrings(MyList); } Контейнерные списочные классы TStringList и TList решают пробле- му динамического распределения памяти. Хотя списочные классы TStringList и TList не являются прямыми потомками одного предка, од- нако они имеют много общих методов: Add() – добавить элемент в конец 54 списка; Clear() – очистить список; Delete() – удалить элемент с указан- ным номером; Exchange() – поменять два элемента местами; Insert() – вставить элемент в указанную позицию; Move() – переместить элемент из одной позиции в другую; Sort() – отсортировать список. Важным до- полнением к перечисленным методам является свойство Count, содер- жащее текущее число элементов в списке. Класс TStringList является потомком класса ТStrings, наследующим свойства и методы родителя. Однако TStrings это абстрактный базовый класс, который не способен производить объекты. Ниже приводится пример инициализации списка типа TStringList в конструкторе главной формы: void _fastcall TForml::TForml(TComponent* Owner) : TForm(Owner) { TStringList * MyList; MyList = new TStringList; // создать объект MyList->Add("Раз"); MyList->Add("Два"); MyList->Add("Три"); MyList->Duplicates = dupIgnore; // игнорировать дубликаты MyList->Sorted = true; // сортировка списка ListBox1->Items->AddStrings(MyList); // отображение списка } Метод Add() добавляет в конец списка строку вместе с указателем на сопровождающий объект. Метод AddStrings() добавляет в конец списка группу строк, взятых из другого списочного объекта. Метод Find() выда- ет номер строки в отсортированном списке и возвращает значение false, если такой строки нет в списке. Метод IndexOf() возвращает номер стро- ки, под которым она впервые встретилась в списке (как отсортирован- ном, так и нет). Метод LoadFromFile() загружает строки списка из тек- стового файла. Метод SaveToFile() сохраняет список в текстовом файле Для хранение объектов используется другой списочный класс TList. Ниже приводится пример использования класса TList для хранения раз- личных объектов (модуль Unit2.cpp). Конструктор главной формы созда- ет список MyList, а затем заносит в него названия файлов, содержащих значки выполняемых программ, и сами значки. TList* MyList; // объявление в файле Unit2.h // Инициализация списка конструктором главной формы __fastcall TForm2::TForm2(TComponent* Owner) : TForm(Owner) { MyList = new TStringList; // создать объект MyList // Загрузить файл имен и отобразить их в компоненте ListBox2 ListBox2->Items->LoadFromFile("Names.txt") ; // Перебрать имена программ и сформировать список MyList 55 for (int i=0; i { String str = ListBox2->Items->Strings[i]; int pos=str.LastDelimiter(“.”); // найти символ ‘.’ str.Delete(pos,4); // стереть расширение файла .exe str.Insert(“.ico”,pos); // заменить расширение файла на .ico TIcon* icon = new TIcon; // создать новый объект icon icon->LoadFromFile(str); // загрузить объект icon MyList->AddObject(str, icon); // добавить str, icon в список } } Элементы списка нумеруются, начиная с 0, и адресуются посредст- вом индексируемого свойства Strings[i]. Например, заголовку формы можно присвоить название, взятое из второй строки списка следующим образом: Form1->Caption = MyList->Strings[2]; В ряде случаев удобно интерпретировать строчный список как еди- ную строку текста. Свойство Text содержит все строки списка: Form1->Caption = MyList->Text; Далее приводится реакция на событие выбора строки из списка ListBox2: void__fastcall TForm2::ListBox2Click(TObject *Sender) int i = ListBox2->ItemIndex; // номер строки //Сдвинуть изображение и вывести пиктограмму Label2->Top=8+i*16; // сдвинуть изображение стрелки Image2->Top = i*16; // сдвинуть изображение значка Image2->Picture->Icon = dynamic_cast // Свойство CommaText содержит все строки списка, // разделенные запятыми: Form1->Caption = MyList->CommaText; } Свойство CommaText преобразует список к формату SDF (System Data Format), обеспечивая возможность импорта данных из внешней программы непосредственно в контейнерный объект VCL. При этом лю- бая строка, содержащая пробелы или запятые, заключается в двойные кавычки. Листинг кодового модуля Unit2.cpp, приведенный выше, иллюстри- рует применение метода AddObject() на примере списка, в котором име- на выполняемых программ файла Names.txt ассоциируются с их пикто- граммами (объектами класса TIcon). Конструктор главной формы создает список MyList, объявленный в интерфейсном модуле Unit2.h, а затем за- носит в него названия и изображения пиктограмм. Упомянутое ранее ин- 56 дексируемое свойство Objects содержит типизированный указатель TObject*, поэтому при выборе пиктограммы оператор dynamic_cast пре- образует ее тип обратно к TIcon*. Наиболее характерное свойство списка TList это Capacity, которое содержит максимальную текущую емкость контейнера. Это значение не является пределом, список всегда можно при необходимости расширять и далее. Преимущества этого свойства появляются, когда списки стано- вятся слишком объемными. Дело в том, что алгоритм перераспределения памяти под списочные классы VCL начинает работать медленно при больших размерах контейнера. Если значение свойства Capacity опреде- лить заранее, сразу же после создания списка, перед добавлением в него новых элементов, то этот алгоритм вообще не включается до тех пор, по- ка заданная емкость контейнера не будет исчерпана. Если предполагает- ся хранить большое количество объектов в списке, то его емкость следу- ет определить сразу же после создания: TList* MyList = new TList; MyList->Capacity = 1000; MyList->Add(new TMyObject); // добавить объект Рассмотрим, как можно извлекать объекты из списка. Для динамиче- ского преобразования указателя типа void* обратно к типу TMyObject* (в нашем примере) можно использовать оператор dynamic_cast (TMyObject*)MyList->Items[i] ; Класс TList предназначен для хранения данных любого типа. Адрес- ный указатель void* на объект любого типа передается как параметр та- ким методам, как Add() и Insert(). Класс TList инкапсулирует ряд специа- лизированных методов: First() – возвращает первый указатель списка (элемент индексируемого свойства Items[0]); Last() – возвращает послед- ний указатель списка (элемент индексируемого свойства Items[Count]); Expand() – увеличивает размер списка, когда его текущая емкость Count достигла значения свойства Capacity 3.2. Файлы и потоки C++Builder предоставляет разработчикам несколько способов органи- зации ввода-вывода файлов: • в стиле языка С; • поточные классы стандартного C++; • класс TFileStream из библиотеки VCL. 57 Поточные классы и потоки C++. Классы ifstream и оfstream, ис- пользуемые для чтения и записи в потоки, являются производными от базового класса ios. Класс fstream способен одновременно читать и пи- сать информацию в поток. Под потоками понимают объекты поточных классов. Для использования классов необходимо включить в заголовок модуля файл fstream.h. Открытие файла. Потоки открываются с помощью конструктора или с помощью метода open(). Режим открытия файлов задают флаги-члены данных перечисляемого типа класса ios: enum open_mode { арр, binary, in, out, trunc, ate }; В табл. 2 приведены возможные значения флагов. Таблица 2 Режим Назначение in Открыть для ввода (по умолчанию для ifstream) out Открыть для вывода (по умолчанию для ofstream) binary Открыть файл в бинарном режиме app Присоединять данные; запись в конец файла ate Установить указатель позиционирования на конец файла trunc Уничтожить содержимое, если файл существует (выбирается по умолчанию, если флаг out указан, а флаги ate и арр – нет) Например: ifstream file; file.open("test.dat", ios::in | ios::binary); ofstream file; file.open("test.txt", ios:out | ios::app); |