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


Присваивание объектов


Один объект можно присвоить другому, если оба объекта имеют одинаковый тип. По умолчанию, когда объект A присваивается объекту B, то осуществляется побитовое копирование всех элементов-данных A в соответствующие элементы-данные B. Если объекты имеют разные типов разные, то компилятор выдаст сообщение об ошибке. Важно понимать, одинаковыми должны быть имена типов, а не их физическое содержание. Например, следующие два типа несовместимы.

class ClassName1

{

 int a, b;

public:

 void set (int ia, int ib) {a=ia; b=ib;}

};

class ClassName2

{

 int a, b;

public:

 void set (int ia, int ib) {a=ia; b=ib;}

};



Так что попытка выполнить

ClassName1 c1;

ClassName2 c2;

c2 = c1;

окажется неудачной.

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

class Pair

{

 int a, *b;

public:

 void set (int ia, int ib) {a=ia; *b=ib;}

 int getb (){return *b;}

 int geta (){return a;}

};

main()

{

 Pair c1,c2;

 c1.set(10,11);

 c2 = c1;

 c1.set(100,111);

 cout << 'с2.b = '<< c2.getb();

}

В результате работы программы получим "c2.b = 111", а не 11, как ожидалось.

Чтобы избежать такого рода недоразумений, используют перегруженный оператор присваивания, в которой явным образом описается (т.е. контролируется) процесс присваивания элементов-данных одного объекта соответствующим элементам-данных другого объекта.

class Pair

{

 int a, *b;

public:

 Pair operator = (Pair p)

 {

  a = p.a;

  *b = *(p.b);

  return *this;

 }

 ...

};

А вот как теперь будет выглядеть наш пример с трехмерным вектором.

class _3d

{

 double x, y, z;

public:

 _3d ();

 _3d (double initX, double initY, double initZ);

 double mod () {return sqrt (x*x + y*y +z*z);}


 double projection (_3d r) {return (x*r.x + y*r.y + z*r.z) / mod();}

 _3d operator + (_3d b);

 _3d operator = (_3d b);

};

_3d _3d::operator = (_3d b)

{

x = b.x;

y = b.y;

z = b.z;

return *this;

}

Наивно было бы предполагать, что для каждой новой переменной типа _3d создается копия функции, реализующей операторы "+" и "=". Каждая функция представлена в единственном экземпляре и в момент вызова получает один скрытый параметр - указатель на экземпляр переменной, для которого она вызвана. Этот указатель имеет имя this. Если используемая переменная не описана внутри функции, не является глобальной, то считается, что она является членом структуры и принадлежит рабочей переменной this. Поэтому при реализации функций операторов мы опускали путь доступа к полям структуры, для которой этот оператор будет вызываться.

В качестве аргументов функций-операторов выступают операнды, а возвращаемое значение - результат применения оператора. В частности для оператора "=" это необходимо, чтобы обеспечить возможность последовательного присваивания (a=b=c). Бинарные операторы имеют один аргумент - второй передается через указатель this. Унарные, соответственно, один - this.


Содержание раздела