Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Cout « x.GetCO; // Отображает статический член с

Поиск

Размещение объектов по заданным адресам

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

В листинге 15.15 демонстрируется размещение объекта по заданному адресу. В программе также приводит­ся пример непосредственного вызова деструктора — необычный прием, который может пригодиться для уда­ления объектов, созданных перегруженным оператором new, использующим нестандартные способы выделе­ния памяти.

«include <iostream.h>

Class TPersist {

Privet:

Int x,y;

Public:

TPersist(int a, int b) { x = а; у = b; }

~TPersistO { x = 0; у = 0; }

void *operator new(size_t, void *p) { return p; }

friend ostream& operator<< (ostream &os, TPersist &p);

};

char object[sizeof(TPersist)];

main() {

TPersist *p = new(object) TPersist(10, 20);

cout «*p «endl;

cout «"Address of object == " «&object «endl;

cout << "Address of *p == " «&(«p) «endl;

p->TPersist::~TPersist();

p->~TPersist(); // Непосредственный вызов деструктора

return 0; // Можно в ВС++ версии 4.0; нельзя в 3.1

}

ostream& operator«(ostream& os, TPersist &p) {

os << "x == " << p.x «", у == " «p.у;

return os;

}

В классе TPersist оператор new перегружается необычным способом. Вместо того чтобы выделить память для указателя, функция перегрузки оператора просто возвращает указатель р типа void. В программе в строке 17 опе­ратор new используется для сохранения объекта класса TPersist в глобальном буфере, определенном в строке 13. Выражение new(object) вызывает перегруженную функцию-член оператора, передавая ей адреса символьного бу­фера object. Поскольку перегруженный оператор new просто возвращает переданный ему указатель р, этот не­сколько странно выглядящий оператор в действительности присваивает указателю р адрес объекта, а также вы­зывает конструктор класса TPersist для инициализации нового, выделенного в буфере объекта.

В программе отображаются адреса символьного буфера object и объекта в буфере. Эти адреса идентичны, что свидетельствует о размещении объекта в указанном месте.

Неплохим упражнением будет запуск PERSIST из отладчика Turbo Debugger. Проследите за содержимым буфера object во время пошагового выполнения кода с помощью клавиши <F8>. После выполнения строки 17 вы увидите, что в глобальном буфере появились значения 10 и 20; это доказывает, что перегруженный опера­тор new не пользовался стандартными средствами выделения памяти в куче.

В строке 21 вызывается деструктор класса для объекта, адресуемого р. Поскольку объект содержится в глобальной переменной, может возникнуть необходимость в вызове деструктора именно таким способом для выполнения действий по очистке объекта. Для невиртуальных деструкторов следует использовать приводя­щийся в листинге оператор следующего вида:

p->TPersist:: TPersistO;

// Непосредственный вызов деструктора

C++ не распознает область действия объекта, сохраненного в буфере, и не может вызвать деструктор клас­са автоматически. Опять же, будет весьма поучительно выполнить этот оператор из Turbo Debugger. Если вы это сделаете, то увидите, как встраиваемые в код операторы деструктора обнуляют данные-члены объекта (строки 8 и 21).

Для виртуальных деструкторов, даже в случае с объектами производных классов, можно использовать сле­дующую форму вызова деструктора:

p->~TPersist(); // Непосредственный вызов деструктора

В Borland C++ 3.1 подобное упрощение синтаксиса запрещено.

Инициализация членов

Объекта класса

В конструкторе обычно инициализируются данные-члены объекта класса. Например, в классе TAnyClass объявляются два целочисленных данных-члена х и у, инициализирующихся с помощью операторов присваива­ния во встраиваемом конструкторе:

class TAnyClass {

Private: i

int x, у;

public:

TAnyClass(){x=0,y=0}

……..

};

В качестве альтернативы вы можете инициализировать члены так, как если бы они имели конструкторы:

class TAnyClass { private:

int x, у; public:

TAnyClassO: x(0), y(0) { }

};

В этой версии конструктора TAnyClass членам х и у присваиваются нулевые значения аналогично тому, как это делалось с помощью присваиваний в предыдущем примере.

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

Этот прием особенно полезен для инициализации объектов других классов.

Например, предположим, что класс TAnyClass имеет член-объект класса TNewClass и конструктору класса TNewClass необходим один целочисленный параметр:

class TNewClass {

int x;

public:

TNewClass(int n) { x = n; }

Если в классе TAnyClass объявляется член типа TNewClass, конструктор TAnyClass обязан инициализиро­вать этот объект. Поскольку конструктор не может быть вызван непосредственно, объект должен инициализироваться с помощью альтернативного способа, описанного ранее:

class TAnyClass {

private:

int x;

TAnyClass(int n): z(n)

{ x = n; }

…..

};

 

Член класса х, как и раньше, имеет тип int. Член z — объект класса TNewClass. Конструктор класса TAnyClass объявляется с целочисленным параметром п, использующимся для инициализации z перед выпол­нением тела конструктора. Внутри конструктора с помощью присваивания значение п запоминается в члене х. Если в классе имеется несколько объектов-членов, вы можете инициализировать их, перечислив и разделив запятыми, следующим образом:

 

TNewClass a, b, z;

// Три объекта-члена класса

Privat:

Int x;

TNewClass z;

public:

TAnyClass(int n): a(n), b(n), z(n)

// Инициализация a, b и z

{ x = n; // Инициализация х

…..

};

 



Поделиться:


Последнее изменение этой страницы: 2016-08-01; просмотров: 205; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.145.12.0 (0.012 с.)