Vector Vector:: operator++(int);
friend Vector operator++(Vector& v, int);
определяют постфиксную модификацию при переопределении операции ++ методом класса или внешней функцией. Если реализация тела префиксной операции ++ очевидна, то постфиксная модификация требует пояснений. Возвращаемое функцией значение вектора должно быть старым, а содержимое объекта, пославшего сообщение, следует изменить на новое, вычисленное в соответствии с приведенными формулами. Таким образом, описание класса Vector можно дополнить двумя методами:
Vector operator++() // Префиксная ++
{
double d=!*this, dn=(d+1.)/d;
x1 *= dn; x2 *= dn;
return *this;
}
Vector operator++(int) // Постфиксная ++
{
Vector temp=*this; // Запоминаем старый вектор
double d=!*this, dn=(d+1.)/d;
x1 *= dn; x2 *= dn; // Новые значения компонент
return temp; // Результат выражения - старый
}
Обратите внимание: d=!*this; вычисляет норму вектора, пославшего сообщение. Здесь * — означает разадресацию, ! — означает уже переопределенную операцию взятия нормы. Для проверки функционирования вновь введенных операций в конец функции main можно добавить строки:
a=++b;
printf ("\n Norm of a=++b:\t\t %6.2f",!a);
b=a++;
printf ("\n Norm of b=a++:\t\t %6.2f",!b);
printf ("\n After a++ the norm of a:%6.2f",!a);
Если постфиксная модификация работает корректно, то последнее выведенное число должно быть на единицу больше, чем предпоследнее. Операция -- может быть переопределена аналогичным образом. Класс Vector выглядит далеко не полным. Разумно было бы дополнить его методами вычисления угла между двумя векторами, вычисления векторного произведения и другими. Не хватает также методов для ввода и вывода компонент вектора. Последние эффективно могут быть выполнены с помощью процедур библиотеки iostream.h, которые мы рассмотрим ниже.
Можно ли в функции operator=() изменить тип возвращаемого значения на Vector&? Что при этом изменится? Будет ли работать программа, если функцию operator=() переписать в виде:
void operator=(Vector& v) { x1=v.x1; x2=v.x2; };
Будет ли работать цепочка присвоений c=a=a; в условиях предыдущего вопроса? Почему после присвоения b=a++; значения переменных a и b не равны? Докажите анализом кодов функции operator++().
Гибкость языка программирования в значительной степени определяется трудоемкостью подстройки существующих программных модулей к новым требованиям заказчика ПО. Степень полезности уже разработанных частей ПО значительно повышается, если существует возможность, не изменяя того, что написано, добавлять к ним новые свойства, модифицировать их функционирование или убирать свойства, ставшие ненужными, наследуя при этом большую часть свойств. В языке Smalltalk, так же как и в C++ в распоряжение программиста предоставлена целая иерархия классов и подклассов. Большинство программ на этих языках пишется с использованием сотен существующих классов и тысяч методов, которые объединены в библиотеки. Появляется возможность создавать объекты существующих классов, и посылать им сообщения в виде методов, или создавать классы, производные от существующих, изменив в них то, что надо, и работать с объектами этих новых классов. Бурно развивающийся С++ предоставляет широкие возможности для создания иерархии классов и подклассов. Библиотеки С++ интенсивно разрабатываются, многие из них уже зарекомендовали себя, как мощные и универсальные средства разработки ПО. Упомянем наиболее известные библиотеки классов: Borland OWL (Object Windows Library), MFC (Microsoft Foundation Classes) Windows Foundation Classes for Java (WFC). Следует отметить, что для использования всей мощи какой-либо библиотеки требуются значительные усилия, временные затраты и достаточно высокая квалификация пользователя, владеющего технологией ООП.
Производный (Derived или Child) класс является основой для реализации механизма наследования свойств базового (Base или Parent) класса, а также средством подстройки класса к нуждам пользователя. Первые версии языка С++ позволяли подклассу иметь только одного родителя, один базовый класс. Теперь подкласс может наследовать черты нескольких базовых классов, что существенно увеличивает гибкость и мощь механизма наследственности. Подкласс (или производный класс) наследует все данные и методы базового класса. В дополнение к ним он может приобрести новые данные и методы, не содержащиеся в базовом классе, но необходимые для конкретных целей, преследуемых при создании подкласса. Каждый объект производного класса содержит свои собственные копии данных, унаследованных от базового класса. Кроме того, в нем обычно декларируются какие-то другие, новые данные, отсутствующие в базовом классе. Любой класс может стать базовым, если создать новый класс, объявив его производным от первого. Рассмотрим пример, в котором три класса образуют иерархию классов (рис. П.3). Здесь класс Man является родительским для двух других классов Stud и Prof.
Заметьте, что стрелки, как в генеалогии, принято проводить в направлении от дочерних классов к родительским. Оба производных класса получили в наследство от класса Man по две переменных (имя и возраст), но далее они завели себе дополнительные другие переменные: Stud — номер курса (course), а Prof — количество статей и название кафедры (publ и dept). Реализуем это в виде кодов.
//============== Global types and variables ===================//
enum eSortBy { None, ByName, ByAge, ByStatus };
const int gNameSize = 15, gDeptSize = 20, gBufSize = 256;
char buf[gBufSize];
//===================== Global funcs ======================//
void Clear (istream& is) //------- Clear keyboard buffer
{
if (cin.eof())
return;
int n = is.rdbuf()->in_avail(); // How many bytes left?
while (n--) // Eat out all of them
is.rdbuf()->sbumpc();
is.clear(); // Clear the failbit
}
int In (string s, int min, int max) //------- Safe Input
{
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.