Присваивание против инициализации

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

C& C::operator=(C&);

Так как операция присваивания возвращает ссылку на объект, она может использоваться в цепочке таких операций.

Инициализация происходит либо при по членном копировании, либо при использовании конструктора следующего вида:

C:: C(&C);

Желательно включение конструктора инициализации.

Инициализация происходит в следующих случаях:

Объявление переменной vect second=first;

Возврат автоматической переменной из функции. Возвращаемое значение - это новый объект, который инициализируется при помощи конструктора.

Передача значения функции в качестве параметра. Параметр действует как локальная переменная и инициализируется при помощи конструктора.

Рассмотрим примеры инициализации:

class demo {

int i;

public:

demo(void) {i=0; }

demo(int i1):i(i1) {}

demo(demo &a) { i=a.i; }

demo &operator=(demo &a) { i=a.i; return *this; }

};

demo copydemo(demo a) {

demo temp; // конструктор без параметров

temp=a; // оператор присваивания

return temp; // вызов конструктора инициализации, временная копия

}

void main(void) {

demo *ptr=new demo(5); // вызывается конструктор с одним параметром

demo demo2=demo1; // вызов инициализирующего конструктора

demo demo3; // вызов конструктора без параметров

demo3=demo2=demo1; // перегруженная операция присваивания вызывается 2 раза

demo4=copydemo(demo1); // вызывается конструктор инициализации для передачи аргумента, по выходе оператор присваивания.

}

Конструктор копирования должен быть определен, если класс содержит поля, являющиеся указателями на динамически распределяемую память. При отсутствии конструктора копирования, конструктор копирования по умолчанию сделает так, что указатель b объекта v и указатель b объекта а будут иметь одинаковые значения. По той же причине необходимо перегружать операцию присваивания, если конструктор копирования перегружен пользователем. Инициализация объекта из другого объекта того же класса может быть запрещена, если конструктор копирования просто объявить в закрытой части класса.

Int a(100);

Int b(a); // Объявить b, которое равно a

Int c=a; // То же в альтернативной форме

Перегруженные операции new delete, ->

Операции new и delete предоставляют классу механизм управления собственной памятью. Тип возвращаемого значения для new - void *, для delete - void. Неявно они являются статическими функциями-членами и, следовательно, не могут быть не константными не виртуальными.

class X {

public:

void *operator new(size_t sz) { return malloc(sz); }

void operator delete(void *p) { free(p); }

};

Если операции new и delete определены для класса, не могут быть вызваны при выделении и освобождении памяти для массивов объектов данного класса. Операция new может быть перегружена, чтобы принимать дополнительные аргументы. Передаваемые аргументы, заключенные в скобки, помещаются при вызове после ключевого слова new.

class T {

public:

// Добавить дополнительный аргумент buf, который будет использоваться для

// выделения памяти для T по указанному адресу

void * operator new(size_t size,void *buf) { /* Разместить T по адресу buf */}

};

char buffer[1000];

T *p=new (buffer) T;

Для объектов класса X вместо операций new, delete будет использоваться X::operator new, X::operator delete.

Перегруженная операция new с дополнительными аргументами скрывает глобальную операцию::operator new. Теперь при обращении к new с обычным синтаксисом произойдет ошибка.

T *p=new T; // ошибка: отсутствует аргумент

Чтобы снова использовать обычный синтаксис оператора new, для класса должна быть предусмотрена функция-член new, имеющая только один аргумент - size_t size. Она явно вызывает глобальную операцию::operatot new.

class T {

public:

void * operator new(size_t size,void *buf) { /* Разместить T по адресу buf */}

void * operator new(size_t size) { return::operator new(size); }

};

Перегруженная операция -> обычно используется в классах, которые содержат в качестве поля указатель на другой класс.

struct A { int *intptr; };

class B { A *a;

public:

B(void) { a=new A; } A *operator->(void) { return a; }

};

B b; *(b->inptr)=15; // = b.a->inptr;


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: