Работа по С++ (1021520), страница 3
Текст из файла (страница 3)
Контрольные вопросы
-
Что такое «конструктор», формат объявления, его особенности?
-
Формат объявления деструктора, его назначение
-
Особенности дружественных функций, доступ к закрытой части класса
-
Каким образом дружественная функция получает доступ к закрытой части класса?
Работа № 4.
Класс «Динамическая строка» и перегрузка операций
Теоретические сведения
Задание к работе
Варианты заданий
Контрольные вопросы
Цель работы – изучить методику создания одномерных динамических символьных массивов при помощи конструкторов с захватом динамической памяти и деструкторов для их уничтожения, а так же способа работы со строковыми объектами. Познакомиться с механизмом перегрузки операций.
Теоретические сведения
Для представления символьной (текстовой) информации можно использовать символы, символьные переменные и символьные константы.
Символьная константа представляется последовательностью символов, заключенной в кавычки: “Начало строки \n”. В С++ нет отдельного типа для строк. Массив символов - это и есть строка. Количества элементов в таком массиве на один элемент больше, чем изображение строки, т. к. в конец строки добавлен ‘\0’ (нулевой байт).
Присвоить значение массиву символов с помощью обычного оператора присваивания нельзя. Поместить строку в массив можно либо при вводе, либо с помощью инициализации:
char s[] = “ABCDEF”;
Для работы со строками существует специальная библиотека string.h. Примеры функций для работы со строками из библиотеки string.h в таблице 2:
Таблица 2 - Функции работы со строками
Функция | Прототип и краткое описание функции |
strcmp | int strcmp(const char *str1, const char *str2); |
strcpy | char* strcpy(char*s1, const char *s2); |
strdup | char *strdup (const char *str); |
strlen | unsigned strlen (const char *str); |
strncat | char *strncat(char *s1, const char *s2, int kol); |
strncpy | char *strncpy(char *s1, const char *s2, int kol); |
strnset | char *strnset(char *str, int c, int kol); |
Строки, при передаче в функцию, в качестве фактических параметров могут быть определены либо как одномерные массивы типа char[], либо как указатели типа char*. В отличие от обычных массивов в этом случае нет необходимости явно указывать длину строки.
Функции преобразования строки S в число:
целое: int atoi(S); длинное целое: long atol(S); действительное: double atof(S); при ошибке возвращает значение 0.
Функции преобразования числа V в строку S:
целое: itoa(int V,char S,int kod); длинное целое: ltoa(long V,char S,int kod); 2<=kod<=36, для отрицательных чисел kod=10.
Перегрузка операций
Для перегрузки операции для класса в С++ используется следующий синтаксис:
<Тип> operator <операция>(<входные параметры>)
{
<операторы>;
}
где < Тип > - тип, возвращаемый функцией;
operator - ключевое слово;
< операция > - перегружаемая операция.
В языке С++ имеются следующие ограничения на перегрузку операций:
-
С++ не различает префиксную и постфиксную формы ++ и - -;
-
переопределяемая операция должна присутствовать в языке (например, нельзя определить операцию с символом #);
-
нельзя переопределить операторы, заданные следующими символами . * :: ? ;
-
переопределённые операции сохраняют свой изначальный приоритет.
Наличие в классе конструктора String:: String(String&) и операторов присваивания позволяет защитить объекты класса от побитового копирования.
Пример: Ввести с клавиатуры строку символов. Признак окончания ввода строки - нажатие клавиши "Ввод". Программа должна определить длину введенной строки L и если L<10 – возвратить строку, которая не содержит заглавных латинских букв.
#include <iostream.h>
#define SIZE 255 //длина строки по умолчанию
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <istream.h>
class X{
char *str;
char *str_return;
public:
X(); //конструктор по-умолчанию
X(char*); //конструктор, которому можно передавать параметр
~X(); //деструктор
char* Run(); //метод, выполняющий поставленную задачу.
void Set(char*);
friend void print(X&); //функция-друг печати
friend ostream& operator<<(ostream&,X&); //перегрузка оператора вывода
friend istream& operator>>(istream&,X&); //перегрузка оператора ввода
friend char* Run(X&); //функция-друг, выполняющий поставленную задачу.
};
X::X(){
str=new char[SIZE];
str[0]='\0';
str_return=new char[SIZE];
str_return[0]='\0';
};
X::X(char *s){
str=new char[SIZE];
strcpy(str,s);
str_return=new char[SIZE];
str_return[0]='\0';
};
X::~X(){
delete[] str;
cout<<"...destructor has been called"<<endl;
};
void X::Set(char* s){
for (unsigned int i=0;i<strlen(s);i++)
str[i]=s[i];
str[i]='\0';
};
char* X::Run(){ /*метод, решающий конкретную задачу, в данном случае - выделение из строки подстроки, не содержащей заглавных латинских букв, если длина исходной строки меньше 10*/
int j=0;
if (strlen(str)<10) {
for (unsigned int i=0;i<strlen(str);i++)
if ( ((int)str[i]<65) || ((int)str[i]>90) ) {
str_return[j]=str[i]; j++;
};
str_return[j]='\0';
}
else strcpy(str_return,str);
return str_return;
};
char* Run(X &obj){return obj.Run();};
void print(X &obj){cout<<obj.str<<" "<<obj.str_return<<endl;};
ostream& operator<<(ostream &stream,X &ob) {
stream << ob.str ;
return stream;
};
istream &operator>>(istream &stream,X &ob){
stream >> ob.str;
return stream;
};
void main (void){
char s[265];
cout<<"Type anything and press \"Enter\":"<<endl;
cin.getline(s,256); //считываем полностью всю строку
X str(s); //доступ к методам класса непосредственно через переменную,
//начальное значение устанавливаем через конструктор
cout<<"You have type:"<<endl;
print(str);
cout<<"Output string:"<<endl;
cout<<Run(str)<<endl;
cout<<"Type anything and press \"Enter\":"<<endl;
cin.getline(s,256);
X *pstr; //доступ к методам класса через указатель
pstr=new X();
pstr->Set(s);
cout<<"You have type:"<<endl;
print(*pstr);
cout<<"Output string:"<<endl;
cout<<Run(*pstr)<<endl;
delete pstr;
};
Задание к работе
Общая постановка. Пользовательский класс String должен содержать необходимые элементы-данные, которые создаются в динамической области памяти.
-
Конструктор для создания строк: String (…);
-
Деструктор: ~String();
-
Метод ввода исходной строки: Set();
-
Метод печати: void print(…);
Код методов – вне пространства определения класса. Программа иллюстрирует прямой и косвенный способы обращения к методам.
Ввести с клавиатуры строку символов S1. Признак окончания ввода строки - нажатие клавиши "Ввод". Программа должна содержать перегруженную операцию «=» , использование которой скопирует S1 в S2 .
Исходную и преобразованную строки вывести в файл.
Варианты заданий
-
Длина L нечетная, то удаляется символ, стоящий посередине строки;
-
Длина L четная, то удаляются 2 первых и 2 последних символа;
-
Длина L кратна 2-м, то удаляются все числа, которые делятся на 2;
-
Длина L кратна 3-м, то удаляются все числа, делящиеся на 3;
-
Длина L >10, то удаляются все цифры;
-
Длина L >15, то удаляются все a..z;
-
Длина L=10, то удаляются все A..Z;
-
Длина L кратна 4-м, то первая часть строки меняется местами со второй;
-
Длина L кратна 5-и, то подсчитывается количество скобок всех видов;
-
Длина L >5-и, то выделяется подстрока до первого пробела;
-
Длина L >6-и, то выделяется подстрока { } скобках;
-
Длина L >10-и, то удаляется подстрока в [] скобках;
-
Длина L >12-и, то удаляется подстрока до первой ( скобки;
-
Длина L кратна 4-м, то выделяется подстрока после последнего пробела;
-
Длина L >5, то удаляются все точки.
-
Длина L четная, то выделяется подстрока до первого пробела
-
Длина L четная, то удаляется подстрока до первого пробела
-
Длина L четная, то выделяется подстрока со второго пробела
-
Длина L нечетная, то выделяется подстрока после первого пробела
-
Длина L нечетная, то удаляется подстрока со второго пробела
-
Длина L кратна 3, то удаляется каждый 3-й символ
-
Длина L четная, то удаляется каждый 2-й символ
-
Длина L нечетная, то
-
Длина L четная, то выделяется подстрока до последнего пробела
-
Длина L нечетная, то выделяется подстрока от последней цифры
-
Длина L=15, то удаляются все символы кроме A-Z
-
Длина L делится на 5, то удаляется все символы кроме a-z
-
Длина L четная и >=10, то удаляются все пробелы
-
Длина L нечетная и <12, произвести инверсию (abcdef->fedcba)
-
Длина L >5 и <30, изменить регистр символов (aBcDeF->AbCdEf)
Контрольные вопросы
-
Как объявить динамическую строку в С++?
-
Какие вы знаете функции работы со строками?
-
Как определяются строки при передаче в функцию, в качестве фактических параметров?
-
Поясните механизм перегрузки операций для объектов данного класса.
Работа № 5.
Наследование классов, механизм виртуальных функций
Теоретические сведения
Задание к работе
Варианты заданий
Контрольные вопросы
Цель работы – изучить одну из базовых концепций ООП – наследование классов в С++, заключающуюся в построении цепочек классов, связанных иерархически. Познакомиться с механизмом виртуальных функций.
Теоретические сведения
Наследование - механизм создания производного класса из базового. Т.е., к существующему классу можно что-либо добавить, или изменять его каким-либо образом для создания нового (производного) класса. Это мощный механизм для повторного использования кода. Наследование позволяет создавать иерархию связанных типов, совместно использующих код и интерфейс. Модификатор прав доступа используется для изменения доступа к наследуемым объектам в соответствии с правилами, указанными в таблице 1.
Таблица 1 – Доступ в классах при наследовании
Доступ в базовом классе | Модификатор прав доступа | Доступ в производном классе |
private | private | не доступны |
private | public | не доступны |
protected | private | private |
protected | public | protected |
public | private | private |
public | public | public |
Ограничение на наследование
При определении производного класса не наследуются из базового:
-
конструкторы;
-
деструкторы;
-
операторы new, определенные пользователем;
-
операторы присвоения, определенные пользователем;
-
отношения дружественности.
Использование косвенной адресации с установкой указателей на базовый класс. Механизм косвенной адресации рассмотрим на примере:
class B
{
public:
int x;
B() { // Конструктор по умолчанию
x = 4; }
};
class D : public B { // Производный класс
public:
int y;
D()
{ // Конструктор по умолчанию
y = 5; }
};
void main(void) {
D d;// Конструктор класса D создает объект d
B *p; // Указатель установлен на базовый касс
p = &d;// Указатель p инициализируется адресом d
// косвенное обращение к объектам базового и производного классов
// «считываем их текущее состояние в переменные
int i = p -> x; // Базовый класс виден напрямую
int j = ( ( D* ) p )p -> y;// Прямое преобразование указателя на D
// через переменные печатаем их текущее состояние
cout << “ x_i= “ << i << endl;
cout << “ y_j= “ << j << endl;
getch();
}
Виртуальная функция и механизм позднего связывания