7.13 Предостережения
Как и всякое другое языковое средство, перегрузка операций может использоваться разумно и
неразумно. В частности, возможностью придавать новый смысл обычным операциям можно
воспользоваться так, что программа будет совершенно непостижимой. Представьте, каково будет
читателю, если в своей программе вы переопределили операцию + так, чтобы она обозначала
вычитание. Описанный здесь механизм перегрузки будет защищать программиста и пользователя от
таких безрассудств. Поэтому программист не может изменить ни смысл операций над основными
типами данных, такими, как int, ни синтаксис выражений и приоритеты операций для них.
По всей видимости перегрузку операций имеет смысл использовать для подражания традиционному
использованию операций. Запись с обычным вызовом функции можно использовать в тех случаях,
когда традиционной записи с базовой операцией не существует, или, когда набор операций, которые
допускают перегрузку, не достаточен, чтобы записать с его помощью нужные действия.
7.14 Упражнения
1. (*2)
Определите итератор для класса string. Определите операцию конкатенации + и операцию += ,
значащую "добавить в конец строки". Какие еще операции вы хотели бы и смогли определить для
этого класса?
2. (*1.5) Определите для строкового класса операцию выделения подстроки с помощью перегрузки ().
3. (*3)
Определите класс string таким образом, чтобы операцию выделения подстроки можно было
применять к левой части присваивания. Вначале напишите вариант, в котором строку можно
присваивать подстроке той же длины, а затем вариант с различными длинами строк.
4. (*2) Разработайте класс string таким образом, чтобы объекты его трактовались при передаче
параметров и присваивании как значения, т.е. чтобы в классе string копировались сами
представления строк, а не только управляющие структуры.
5. (*3)
Измените класс string из предыдущего упражнения так, чтобы строки копировались только при
необходимости. Это значит, что нужно хранить одно общее представления двух одинаковых строк
Бьерн Страуструп.
Язык программирования С++
202
до тех пор, пока одна из них не изменится. Не пытайтесь задать операцию выделения подстроки,
которую одновременно можно применять и к левой части присваивания.
6. (*4) Определите класс string, обладающий перечисленными в предыдущих упражнениях
свойствами: объекты его трактуются как значения, копирование является отложенным (т.е.
происходит только при необходимости) и операцию выделения подстроки можно применять к левой
части присваивания.
7. (*2)
Какие преобразования типа используются в выражениях следующей программы?
struct X {
int
i;
X(int);
operator+(int);
};
struct Y {
int
i;
Y(X);
operator+(X);
operator
int();
};
extern X operator*(X,Y);
extern int f(X);
X x = 1;
Y y = x;
int i = 2;
int main()
{
i + 10; y + 10; y + 10 * y;
x + y + i; x * X +i; f(7);
f(y); y + y; 106 + y;
}
Определите X и Y как целые типы. Измените программу так, чтобы ее можно было выполнить и она
напечатала значения всех правильных выражений.
8. (*2)
Определите класс INT, который будет эквивалентен типу int. Подсказка: определите функцию
INT::operator int().
9. (*1) Определите класс RINT, который будет эквивалентен типу int, за исключением того, что
допустимыми будут только операции: + (унарный и бинарный), - (унарный и бинарный), *, / и %.
Подсказка: не надо определять RINT::operator int().
10. (*3) Определите класс LINT, эквивалентный классу RINT, но в нем для представления целого
должно использоваться не менее 64 разрядов.
11. (*4) Определите класс, реализующий арифметику с произвольной точностью. Подсказка: Придется
использовать память так, как это делается в классе string.
12. (*2) Напишите программу, в которой благодаря макрокомандам и перегрузке будет невозможно
разобраться. Совет: определите для типа INT + как -, и наоборот; с помощью макроопределения
задайте int как INT. Кроме того, большую путаницу можно создать, переопределяя широко
известные функции, и используя параметры типа ссылки и задавая вводящие в заблуждение
комментарии.
13. (*3) Обменяйтесь решениями упражнения [12] с вашим другом. Попробуйте понять, что делает его
программа, не запуская ее. Если вы сделаете это упражнение, вам станет ясно, чего надо избегать.
14. (*2) Перепишите примеры с классами complex ($$7.3), tiny ($$7.3.2) и string ($$7.11), не используя
дружественные функции. Используйте только функции-члены. Проверьте новые версии этих
Бьерн Страуструп.
Язык программирования С++
203
классов. Сравните их с версиями, в которых используются дружественные функции. Обратитесь к
упражнению 5.3.
15. (*2) Определите тип vec4 как вектор из четырех чисел с плавающей точкой. Определите для него
функцию operator[]. Для комбинаций векторов и чисел с плавающей точкой определите операции: +,
-, *, /, =, +=, -=, *= и /=.
16. (*3) Определите класс mat4 как вектор из четырех элементов типа vec4. Определите для него
функцию operator[], возвращающую vec4. Определите для этого типа обычные операции с
матрицами. Определите в mat4 функцию, производящую преобразование Гаусса с матрицей.
17. (*2) Определите класс vector, аналогичный классу vec4, но здесь размер вектора должен задаваться
как параметр конструктора vector::vector(int).
18. (*3) Определите класс matrix, аналогичный классу mat4, но здесь размерности матрицы должны
задаваться как параметры конструктора matrix::matrix(int,int).
19. (*3) Завершите определение класса CheckedPtrToT из $$7.10 и проверьте его. Чтобы определение
этого класса было полным, необходимо определить, по крайней мере, такие операции: *, ->, =, ++ и
--. Не выдавайте динамическую ошибку, пока действительно не произойдет обращение по
указателю с неопределенным значением.
20. (*1.5) Перепишите пример с программой подсчета слов из $$7.7 так, чтобы в ней не было заранее
заданной максимальной длины слова.
Бьерн Страуструп.
Язык программирования С++
204
Достарыңызбен бөлісу: |