Массивы объектов, указатели и ссылки

Массивы объектов создаются так же, как и массивы переменных. Если класс содержит конструктор, массив может быть инициализирован, причем конструктор вызывается столько раз, сколько элементов содержит массив.

#include<iostream.h>//пример 40

class Sample{

int a;

public:

Sample(int n){

a=n;

cout<<”constructor\n”;}

int getA(){return a;}

};

int main() {

Sample ob[4]={1,2,3,4};

Sample *pob=ob;

int i;

for(i=0;i<4;i++) cout<<ob[i].getA ()<< ‘ ‘;

cout<<”\n”;

cout<<pob->getA ();

return 0;

}

Программа выведет 1, 2, 3, 4, конструктор вызывается четыре раза. Затем еще раз будет выведено 1 с помощью указателя pob на первый элемент массива. Список инициализации – это сокращение общей конструкции:

Sample ob[4]={Sample(1),Sample(2),Sample(3),Sample(4)};

Такая конструкция становится основной, если конструктор имеет два и более аргумента. Например:

Sample ob[4]= {Sample(1,2),Sample(3,4),Sample(5,6),Sample(7,8)};

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

#include <iostream.h>//пример 41

class Samp {

int i, j;

public:

Samp(){cout<<”конструктор2\n”;}

Samp(int a,int b){i=a;j=b;cout<<”конструктор1\n”;}

void setIJ(int a, int b) { i = a; j = b; }

~Samp() { cout << "удаление...\n"; }

int get() { return i*j; }

};

int main() {

Samp *p01;

int i;

p01 = new Samp(6,5);

Samp *p02;

p02 = new Samp[3];

if(!p01||!p02) {cout << "ошибка выделения памяти\n"; return 1;}

for(i=0; i<3; i++) {

p02[i].setIJ(i, i);

cout << "р02[" << i << "]="<<p02[i].get()<<”\n”;

}

cout << p01->get() << "\n";

delete p01;

delete [ ] p02;

return 0;

}

Результат:

конструктор1

конструктор2

конструктор2

конструктор2

р02[0]=0

p02[1]=1

p02[2]=4

удаление...

удаление...

удаление...

удаление...

Деструктор вызывается 4 раза: по одному разу на каждый элемент массива и один раз для объекта р01.

Ссылки

Ссылка является скрытым константным указателем и работает как другое имя переменной. Ее можно использовать для передачи аргументов в функцию и возврата значений обратно. При передаче объекта через ссылку в функцию сообщается адрес объекта, а его копия не делается. Это уменьшает вероятность ошибок, связанных с выделением динамической памяти и вызовом деструктора. Аналогично, при возврате ссылки на объект из функции также не делается копия объекта.

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

// защищенный двумерный массив

#include <iostream.h>//пример 42

#include <stdlib.h>

class Array {

int isize, jsize;

int *p;

public:

Array(int i, int j) {

p = new int [ i * j ];

if(!p) {

cout << "Ошибка выделения памяти\n";

exit(1); }

isize = i;

jsize = j;

}

int &put(int i, int j);

int get(int i, int j);

};

/* возврат ссылки на элемент массива, в который необходимо выполнить запись */

int &Array::put(int i, int j) {

if(i<0 || i>=isize || j<0 || j>=jsize) {

cout << "Ошибка, нарушены границы массива!!!\n";

exit(1);

}

return p[i * jsize + j]; // возврат ссылки на p[ i ] [ j ]

}

// получение значения из массива

int Array::get(int i, int j) {

if(i<0 || i>=isize || j<0 || j>=jsize) {

cout << "Ошибка, нарушены границы массива!!!\n";

exit(1);

}

return p[i * jsize + j]; // возврат символа

}

int main() {

Array a(2, 3);

int i, j;

for(i=0; i<2; i++)

for(j=0; j<3; j++)

a.put(i, j) = i + j;

for(i=0; i<2; i++)

for(j=0; j<3; j++)

cout << a.get(i, j) << ' ';

// генерация ошибки нарушения границ массива

a.put(10, 10);

return 0;

}

Наши рекомендации