Компания ALT Linux
Опубликован: 07.03.2015 | Доступ: свободный | Студентов: 2136 / 487 | Длительность: 24:14:00
Лекция 10:

Объектно-ориентированное программирование

10.3.3 Пример: класс spatial_vector в сборе

Прежде чем закончить разговор о перегрузке операторов и передаче объектов, приведём ещё один пример, наглядно иллюстрирующий, что иногда передача объекта по значению может нести практическую пользу. Рассмотрим финальный вид класса spatial_vector с перегруженными операторами ввода-вывода, инкремента и декремента обеих форм, а также операторами сложения и вычитания.

#include <iostream>
#include <math.h>
using namespace std;
class spatial_vector
{
	double x, y, z;
public :
	spatial_vector ( double x=0, double y=0, double z=0);
	double abs ( ) { return sqrt ( x*x + y*y + z * z ); }
	double get_x ( ) { return x; }
	double get_y ( ) { return y; }
	double get_z ( ) { return z; }
	void set_x ( double x ) { this->x=x; }
	void set_y ( double y ) { this->y=y; }
	void s et_ z ( double z ) { this->z=z; }
	void info ( );
	spatial_vector& operator++(); //префиксная форма
	spatial_vector& operator--();
	spatial_vector operator++(int ); //постфиксная форма
	spatial_vector operator--(int );
	friend spatial_vector operator+( spatial_vector a,const spatial_vector& b);
	friend spatial_vector operator-( spatial_vector a,const spatial_vector& b);
	friend ostream& operator<<(ostream& stream, const spatial_vector& b);
	friend istream& operator>>( istream& stream, spatial_vector& b);
};
spatial_vector::spatial_vector ( double x1, double y1, double z1 )
{
	x = x1;
	y = y1;
	z = z1;
}
void spatial_vector::info ( )
{
	cout << "Координаты вектора: x = " << x << "; y = " << y << "; z = " << z << endl;
	cout << "Модуль вектора равен " << abs ( ) << endl;
}
spatial_vector& spatial_vector::operator++()
{
	x++; y++; z++;
	return * this;
}
spatial_vector& spatial_vector::operator--()
{
	x--; y--; z--;
	return * this;
}
spatial_vector spatial_vector::operator++(int )
{
	spatial_vector temp=*this;
	++(*this );
	return temp;
}
spatial_vector spatial_vector::operator--(int )
{
	spatial_vector temp=*this;
	--(*this );
	return temp;
}
spatial_vector operator+ ( spatial_vector a,const spatial_vector& b )
{
	//передаём первый аргумент по значению,
	//поэтому можем изменять его, не влияя на исходный объект:
	a.x += b.x;
	a.y += b.y;
	a.z += b.z;
	//возвращаем изменённую копию первого аргумента:
	return a;
}
spatial_vector operator_( spatial_vector a,const spatial_vector& b )
{
	a.x -= b.x;
	a.y -= b.y;
	a.z -= b.z;
	return a;
}
ostream& operator<<(ostream& stream, const spatial_vector& b )
{
	stream << " x = " << b.x << "; y = " << b.y << "; z = " << b.z << endl;
	return stream;
}
istream& operator>>( istream& stream, spatial_vector& b )
{
	stream >> b.x >> b.y >> b.z;
	return stream;
}
main ( )
{
	spatial_vector a,b(1, 2, 3 );
	cout << " \n1. Заполнение вектора через стандартный ввод\n ";
	cout << "Введите координаты вектора: ";
	cin >> a;
	a.info ( );
	cout << " \n2. Вычитание векторов\n ";
	spatial_vector c = a-b;
	cout << "Координаты вектора с=a-b(1,2,3): " << c;
	cout << " \n3. Изменение координаты вектора с помощью геттеров и сеттеров\n ";
	c.set_x ( c.get_x ( ) +1);
	cout << "После инкремента координаты x, координаты вектора c: " << c;
	cout << " \n4. Инкремент:\nвывод с++: " << c++;
	cout << "Вывод ++с: " << ++c;
}

Функция main() просит пользователя ввести с клавиатуры три координаты вектора, а затем выполняет несколько тестов, демонстрирующих работу методов класса. Например, при вводе значений "1 2 3" выводится следующий результат:

1. Заполнение вектора через стандартный ввод
Введите координаты вектора: 1 2 3
Координаты вектора: x=1; y=2; z=3
Модуль вектора равен 3.74166

2. Вычитание векторов
Координаты вектора с=a-b(1,2,3): x=0; y=0; z=0

3. Изменение координаты вектора с помощью геттеров и сеттеров
После инкремента координаты x, координаты вектора c: x=1; y=0; z=0

4. Инкремент:
вывод с++: x=1; y=0; z=0
Вывод ++с: x=3; y=2; z=2

Как можно заметить, в программе не перегружен оператор присваивания, а в классе spatial_vector не задан конструктор копирования. В данном случае класс не работает с динамической памятью и не нуждается в какой-то особой предварительной инициализации и деинициализации, поэтому выполняемое по умолчанию побитовое копирование объектов оказывается полностью приемлемым. Более того, передача параметра по значению активно используется в перегруженных операторах сложения и вычитания, а также в постфиксной форме инкремента и декремента. В первых двух случаях первый параметр (левый операнд) передаётся по значению, чтобы можно было изменить его и вернуть, не затронув исходный объект. В перегруженных постфиксных операторах используется возврат исходной побитовой копии объекта, снятой до того, как оригинальный объект был изменён.

Комбинирование в выражениях перегруженных операторов, некоторые из которых используют передачу по ссылке, а некоторые — по значению, требует тщательности в оформлении списка параметров. Если возвращённый по значению результат работы одного оператора может быть принят другим по ссылке, во избежание конфликтов соответствующий аргумент следует явно объявить константным (см., например, второй параметр оператора потокового вывода). На самом деле использование модификатора const в подобных случаях боле чем логично, поскольку оператор не изменяет принятый аргумент, а передача по ссылке используется исключительно для уменьшения накладных расходов на копирование объекта.

Сергей Радыгин
Сергей Радыгин

Символы кириллицы выводит некорректно. Как сделать чтобы выводился читабельный текст на русском языке?

Тип приложения - не Qt,

Qt Creator 4.5.0 основан на Qt 5.10.0. Win7.

 

Юрий Герко
Юрий Герко

Кому удалось собрать пример из раздела 13.2 Компоновка (Layouts)? Если создавать проект по изложенному алгоритму, автоматически не создается  файл mainwindow.cpp. Если создавать этот файл вручную и добавлять в проект, сборка не получается - компилятор сообщает об отсутствии класса MainWindow. Как правильно выполнить пример?