Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

hkjCJgcQqF

.pdf
Скачиваний:
2
Добавлен:
15.04.2023
Размер:
810.94 Кб
Скачать

функцию, определяющую

число комитетов из k членов, которые можно

сформировать из n человек:

 

int comm (int n, int k)

{

//условие останова : слишком мало народа if (k > n)

return 0;

//условие останова : в комитете все или никого else if (n == k || k == 0)

return 1; else

//шаг рекурсии: все комитеты без персоны A

//плюс все комитеты с персоной A

return comm(n-1,k) + comm(n-1,k-1);

}

Задание

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

Вот функции из библиотеки С, определенные в заголовочном файле <cmath> :

double sin(double); double cos(double); double sqrt(double);

Объявите массив указателей на С-функции и инициализируйте его этими функциями. Напишите main(), которая вызывает sqrt() с аргументами 97.9 через элемент массива.

2. Создайте приложение, в котором определены перегруженные варианты функции error() , чтобы были корректны следующие вызовы:

int undex:

int upperBound; char selectVal; // …

error( “Массив вышел за границы: “, index, upperBound); error( “Деление на нуль” );

error(“Ошибочное выделение”, selectVal);

3.Создайте приложение, в котором имеются следующие описания:

функция с параметрами типа указатель на символ и ссылка на целое, возвращающая значения (void);

указатель на такую функцию;

функция с параметром, имеющим тип такого указателя;

функция, возвращающая такой указатель.

Напишите определение функции, у которой параметр и возвращаемое значение имеют тип такого указателя. Указание : используйте typedef.

53

4. Напишите программу, в которой пользователь вводит число кандидатов и число человек в комитете. На выходе выдается число возможных вариантов комитета.

Контрольные вопросы

1.Зачем может понадобиться объявлять перегруженные функции?

2.Объясните, к какому эффекту приводит второе объявление в каждом из приведенных примеров:

(a)int calc(int, int);

int calc(const int, const int);

(b) int get(); double get();

(c) int * reset ( int *); double * reset ( double *);

(d) extern “C” int compute(int *, int);

extern “C” double compute(double *, double); Ответ подкрепите примером программы

3.Какая из следующих инициализаций приводит к ошибке? Почему?

(a)void reset(int) ;

void (*pf) ( )=reset;

(b) int calc(int, int);

int (* pf1) (int, int)=calc;

(c) extern “C” int compute(int , int); int (*pf3) (int *, int)=compute;

Ответ подкрепите примером программы 4. Каков ранг каждого из преобразований аргументов в следующих вызовах функций:

(a ) void print(int *, int); int arr[7]; print(arr, 7);

(b)void myfunc (int, int); myfunc (‘a’, ‘z’);

(c)int calc (int, int); double dobj=1.7;

double j=calc(55.4, dobj)

(d)void set (const int *);

int *pi; set(pi);

Ответ подкрепите примером программы

(e) int calc(int, int);

int (* pf1) (int, int)=calc;

(f)extern “C” int compute(int , int); int (*pf3) (int *, int)=compute;

54

5. Объясните, что происходит при разрешении перегрузки для вызова функции compute() внутри main()

namespace primerLib { void compute( );

void compute( const void *); } using primerLib::compute; void compute(int);

void compute(double, double=3.4); void compute(char *,char *= 0);

int main() { compute(0); return 0; }

Какие функции являются кандидатами?

Какие из них попадут в список подходящих после первого шага?

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

Какая функция будет наиболее подходящей?

Что будет, если using-объявление поместить внутрь функции main() перед вызовом compute()? Ответьте на те же вопросы.

Задание для самостоятельной работы

1. Возведение числа n в степень p -это умножение числа n на себя p раз. Напишите функцию power(), которая в качестве аргументов принимает значение типа double для n и значение типа int для p и возвращает значение типа double. Для аргумента, соответствующего степени числа, задайте значение по умолчанию, равное 2, чтобы при отсутствии показателя степени при вызове функции число n возводилось в квадрат. Затем создайте перегруженные функции , принимающие в качестве аргумента значения типа char, int, long, float. Напишите программу , вызывающую функцию power() со всеми возможными типами аргументов.

2.Напишите функцию с именем swap(), обменивающую значениями два своих аргумента типа int (обратите внимание, что изменяться должны значения переменных из вызывающей программы , а не локальных переменных функции). Выберите способ передачи аргументов. Напишите функцию(main()), использующую данную функцию.

3.Напишите программу , в которой фактический параметр не может инициализировать параметр-ссылку.

55

Глава 3. Перегрузка операторов и преобразования, определенные пользователем

Процесс, называемый перегрузка оператора, переопределяет стандартные символы операторов для реализации операций для типа класса, т.е. операторы языка, такие как +, !=, [] и = могут быть переопределены для типа класса. Перегрузка операторов позволяет вводить собственные версии предопределенных операторов для операндов типа классов.

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

Спецификация класса MyString

#include <iostream> #include <string.h> #include <stdlib.h> using namespace std; #ifndef NULL const int NULL = 0; #endif // NULL

const int outOfMemory = 0, indexError = 1; class MyString

{

private:

//указатель на динамически создаваемую строку

//длина строки включает NULL символ

char *str; int size;

// функция сообщения об ошибках

void Error(int errorType, int badIndex = 0) const; public:

// конструкторы

MyString(char *s = ""); MyString(const MyString& s);

// деструктор

~MyString( );

// операторы присваивания MyString = MyString, MyString = C++String

MyString& operator= (const MyString& s); MyString& operator= (char *s);

//операторы отношений MyString==MyString, MyString==C++String,

//C++String==MyString ; operator возвращает целочисленное значение ,

//как результат сравнения

int operator== (const MyString& s) const; int operator== (char *s) const;

56

friend int operator== (char *str, const MyString& s);

//MyString!=MyString,MyString!=C++String,C++String!=MyString int operator!= (const MyString& s) const;

int operator!= (char *s) const;

friend int operator!= (char *str, const MyString& s);

//MyString<MyString ,MyString<C++String,C++String<MyString int operator< (const MyString& s) const;

int operator< (char *s) const;

friend int operator< (char *str, const MyString& s);

//MyString<=MyString,MyString<=C++String,C++String<=MyString int operator<= (const String& s) const;

int operator<= (char *s) const;

friend int operator<= (char *str, const String& s);

// String>String,String>C++String,C++String>String int operator> (const String& s) const;

int operator> (char *s) const;

friend int operator> (char *str, const String& s);

// String>=String,String>=C++String,C++String>=String int operator>= (const String& s) const;

int operator>= (char *s) const;

friend int operator>= (char *str, const String& s);

//операторы String-конкатенации MyString+MyString, MyString+C++St, C++St+MyString , MyString +=MyString, MyString += C++St

MyString operator+ (const MyString& s) const; MyString operator+ (char *s) const;

friend MyString operator+ (char *str,const MyString& s); void operator+= (const MyString& s);

void operator+= (char *s);

//MyString -функции

//начиная с первого символа , найти положение символа c int Find(char c, int start) const;

//найти последнее вхождение символа c

int FindLast(char c) const; // выделение подстроки

MyString Substr(int index, int count) const;

//вставить объект MyString в объект MyString void Insert(const MyString& s, int index);

//вставить строку типа C++String в строку типа MyString void Insert(char *s, int index);

//удалить подстроку

void Remove(int index, int count);

57

// String -индексация

char& operator[] (int n);

//преобразовать String в C++String operator char* ( ) const;

//String I/O

friend ostream& operator<< (ostream& ostr, const MyString& s); friend istream& operator>> (istream& istr, MyString& s);

// читать символы до разделителя

int ReadString(istream& is=cin, char delimiter='\n');

// дополнительные методы int Length( ) const; int IsEmpty( ) const; void Clear( );

}; Строковые переменные С++ являются массивами символов с нулевым

символом в конце. В классе MyString определяется строковый тип. Объекты используют динамическую память для сохранения строк переменной длины и перегруженные операторы для создания строковых выражений.

Объекты класса MyString могут взаимодействовать со строками С++ (char*). Класс MyString имеет деструктор, конструктор и два перегруженных оператора присваивания, позволяющие присваивать объект типа MyString или строку С++ новому объекту MyString.

Сначала определим закрытую функцию Error.

void MyString::Error(int errorType, int badIndex=0) const

{

if (errorType == outOfMemory)

cerr << "Memory exhausted!" << endl; else

cerr << "Index " << badIndex << " out of range" << endl;

exit(1); }

// конструктор, выделение памяти и копирование в C++String MyString::MyString(char *s=””)

{

//длина включает NULL символ size = strlen(s) + 1;

str = new char [size];

//программа завершается, если память исчерпана . if (str == NULL)

Error(outOfMemory); strcpy(str,s); }

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

58

MyString::MyString(const String& s) { // текущий объект длиной s

size = s.size;

str = new char [size]; if (str == NULL)

Error(outOfMemory); strcpy(str,s.str); }

//деструктор MyString::~MyString( ) {

delete [] str; }

Перегруженные операторы присваивания в классе MyString

Оператор присваивания позволяет присваивать либо объект MyString, либо строку С++ объекту MyString. Например, создаются два объекта MyString:

MyString S("Hello World!"), T;

// присваивает объект MyString объекту MyString T=S;

//присваивает строку С++ объекту MyString T="I am a C++ String";

Для того, чтобы присвоить новый MyString-объект s текущему объекту, сравнивается длина двух строк. Если они различные , оператор удаляет динамическую память текущего объекта и снова (оператором new) выделяет s.size символов. Затем s.str копируется в новую память.

// operator. MyString to MyString

MyString& MyString::operator= (const MyString& s)

{

if (s.size != size)

{

delete [] str;

str = new char [s.size]; if(str == NULL)

Error(outOfMemory); size = s.size; }

// копировать s.str и возвратить ссылку на текущий объект strcpy(str,s.str);

return *this; }

// оператор присваивания C++String to MyString MyString& MyString::operator= (char *s)

{

int slen = strlen(s) + 1; if (slen != size)

{

delete [] str;

59

str = new char [slen]; if (str == NULL)

Error(outOfMemory); size = slen;

}

strcpy(str,s);

return *this; }

 

Перегруженные операторы сравнения

 

В них используется C++ string функция

strcmp. Можно использовать

возвращаемое значение типа bool.

 

//MyString == MyString

 

int String::operator== (const String& s) const {

return strcmp(str,s.str) == 0; }

 

// MyString == C++String

 

int MyString::operator== (char *s) const

{

return strcmp(str,s) == 0; }

 

//C++String == MyString. дружественная функция

//так как C++String находится в левой части

int operator== (char *str, const MyString& s)

{

return strcmp(str,s.str) == 0;

}

 

 

// MyString != MyString

 

 

 

int String::operator!= (const String& s) const

{

return strcmp(str,s.str) != 0;

}

 

 

// MyString != C++String

 

 

 

int String::operator!= (char *s) const

{

 

return strcmp(str,s) != 0;

}

 

 

// C++String != MyString

 

 

 

int operator!= (char *str, const MyString& s)

{

return strcmp(str,s.str) != 0;

}

 

 

// MyString < MyString

 

 

 

int MyString::operator< (const MyString& s) const {

return strcmp(str,s.str) < 0;

}

 

// MyString < C++String

 

 

int MyString::operator< (char *s) const {

 

return strcmp(str,s) < 0;

}

 

// C++String < MyString

 

 

int operator< (char *str, const MyString& s)

{

return strcmp(str,s.str) < 0;

}

 

Все остальные перегруженные операторы сравнения определяются аналогично.

Конкатенация : -перегруженный operator+

MyString MyString::operator+ (const MyString& s) const {

60

// создание новой строки temp с длиной len MyString temp;

int len;

// удаление NULL string , созданной при объявлении temp delete [] temp.str;

// вычисление длины результирующей строки и выделение памяти в temp len = size + s.size - 1; // только один NULL символ

temp.str = new char [len]; if (temp.str == NULL) Error(outOfMemory);

// установка размера результирующей строки и создание строки

temp.size = len;

 

 

 

 

strcpy(temp.str,str);

// копирование

str в temp

strcat(temp.str, s.str);

// конкатенация

s.str

return temp;

 

// возвратить

temp

}

 

 

 

 

MyString MyString::operator+ (char *s) const

{

 

 

 

 

MyString temp;

 

 

 

 

int len;

 

 

 

 

delete [] temp.str;

 

 

 

 

len = size + strlen(s);

 

 

 

temp.str = new char [len];

 

 

if (temp.str == NULL)

 

 

Error(outOfMemory);

 

 

temp.size = len;

 

 

 

 

strcpy(temp.str,str);

 

 

 

strcat(temp.str, s);

 

 

 

return temp;

}

 

 

 

MyString operator+ (char *cs, const

MyString& s)

{

 

 

 

 

MyString temp; int len;

delete [] temp.str;

len = strlen(cs) + s.size; temp.str = new char [len]; if (temp.str == NULL)

s.Error(outOfMemory); temp.size = len; strcpy(temp.str,cs); strcat(temp.str, s.str); return temp;

}

61

void MyString::operator+= (const MyString& s)

{

char *tempstr; int len;

// вычисляется длина строки конкатенации и выделяется память в tempstr len = size + s.size - 1;

tempstr = new char [len]; if (tempstr == NULL)

Error(outOfMemory);

//копировать строку в tempstr и объединить с s.str strcpy(tempstr,str);

strcat(tempstr, s.str);

//удалить текущую строку

delete [] str;

// новая строка имеет адрес tempstr с длиной len

str = tempstr;

 

size = len;

 

 

}

 

 

void MyString::operator+= (char *s) {

 

int len;

 

 

char *tempstr;

 

len = size + strlen(s);

 

tempstr = new char [len];

 

if (tempstr == NULL)

 

Error(outOfMemory);

 

strcpy(tempstr,str);

 

strcat(tempstr, s);

 

delete [] str;

 

str = tempstr;

 

size = len;

}

 

int MyString::Find(char c, int start) const

{

int ret;

 

 

char *p;

 

 

p = strchr(&str[start],c);

 

if (p != NULL)

 

ret = int(p-str);

 

else

 

 

ret = -1;

 

 

return ret;

}

 

// возвращает индекс последнего вхождения с в строке int MyString::FindLast(char c) const {

int ret; char *p;

62

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]