Член-данные, имеющие тип класса

Пусть имеется класс vect, реализующий защищенный массив, и необходимо хранить несколько значений для каждого такого массива: возраст, вес и рост группы лиц. Группируем 3 массива внутри нового класса.

#include "vect.h" // описание класса vect
class multi_v {

public:

vect a, b, c;

multi_v(int i): a(i), b(i), c(i){}
};

Конструктор нового класса имеет пустое тело и список вызываемых конструкторов класса vect, перечисленных после двоеточия (:) через запятую (,). Они выполняются с целым аргументом i, создавая 3 объекта класса vect: a, b, c.

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

int main() {

multy_v dan(3); // Вызывает 3 конструктора для класса vect

for(int i=0; i<=dan.a.razm(); i++)

{

dan.a.element(i)=10+i;

dan.b.element(i)=20+5*i;

dan.c.element(i)=120+5*i;

}

for(int i=0; i<=dan.a.razm(); i++)

{

cout << dan.a.element(i) << "лет \t";

cout<< dan.b.element(i) << "кг \t";

cout << dan.c.element(i) << "см" << endl;

}

cin.get();

return 0;

}

При выполнении программы перед выходом из блока main для каждого члена vect будет вызываться индивидуальный деструктор. Результат работы программы

10 лет 20 кг 120 см
11 лет 25 кг 125 см
12 лет 30 кг 130 см

 

Билет 15

Вопрос 1:Указатели на функции в языке C.Примеры

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

Память компьютера можно представить в виде последовательности пронумерованных однобайтовых ячеек, с которыми можно работать по отдельности или блоками.

Каждая переменная в памяти имеет свой адрес - номер ячейки, где она расположена, а также свое значение. Указатель — это тоже переменная, которая размещается в памяти. Она тоже имеет адрес, а ее значение является адресом некоторой другой переменной. Переменная, объявленная как указатель, занимает 4 байта в оперативной памяти (в случае 32-битной версии компилятора).

Указатель, как и любая переменная, должен быть объявлен.
Общая форма объявления указателя

тип *имя_объекта;

Тип указателя— это тип переменной, адрес которой он содержит.

Для работы с указателями в Си определены две операции:

· операция * (звездочка) — позволяет получить значение объекта по его адресу - определяет значение переменной, которое содержится по адресу, содержащемуся в указателе;

· операция & (амперсанд) — позволяет определить адрес переменной.

Например,

сhar c; // переменная
char *p; // указатель
p = &c; // p = адрес c


Для указанного примера обращение к одним и тем же значениям переменной и адреса представлено в таблице

  Переменная Указатель
Адрес &c p
Значение c *p

Пример

#include <stdio.h>
#include <stdlib.h>
int main() {

int a, *b;

system("chcp 1251");

system("cls");

a=134;

b=&a;

printf("\n Значение переменной a равно %d.", a);

printf("\n Адрес переменной a равен %d.", &a);

printf("\n Данные по адресу указателя b равны %d.",*b);

printf("\n Значение указателя b равно %d.",b);

printf("\n Адрес расположения указателя b равен %d.", &b);

getchar();

return 0;
}

Результат выполнения программы:

Расположение в памяти переменной a и указателя b:
Необходимо помнить, что компиляторы высокого уровня поддерживают прямой способ адресации: младший байт хранится в ячейке, имеющей младший адрес

 

Вопрос 2:Передача объекта в c++;подробно описать как происходит. Пример

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

#include <iostream.h>
class myclass {
int i;
public:
myclass (int n);
~myclass ();
void set_i(int n) {i=n;}
int get_i() {return i; }
};
myclass::myclass (int n)
{
i = n;
cout << "Constructing " << i << "\n";
}
myclass::~myclass()
{
cout << "Destroying " << i << "\n";
}
void f (myclass ob);
int main()
{
myclass о (1);
f(o);
cout << "This is i in main: ";
cout << о.get_i() << "\n";
return 0;
}
void f (myclass ob)
{
ob.set_i(2);
cout << "This is local i: " << ob.get_i();
cout << " \n";
}

Эта программа выведет на экран следующий текст:

Constructing 1
This is local i: 2
Destroying 2
This is i in main: 1
Destroying 1

Обратим внимание, что имели место два вызова деструктора, в то время как конструктор вызы­вался только один раз. Выведенный текст иллюстрирует, что функция-конструктор не вызывается, когда копия объекта о (в программе main()) передается переменной ob (внутри функции f()). Причина, по которой конструктор не вызывался при создании копии объекта, может быть легко понята. Когда объект передается в функцию, нужно текущее состояние этого объекта. Если бы при создании копии вызывался конструктор, то осуществлялась бы инициализация объекта, ко­торая бы изменила его состояние. Поэтому конструктор не может вызываться при создании ко­пии объекта для передачи в функцию.

Хотя функция-конструктор не вызывалась при передаче объекта в функцию, необходимо вызы­вать деструктор при уничтожении копии. (Копия объекта уничтожается, как и любая локальная переменная, после окончания выполнения функции.) Надо иметь в виду, что копия объекта су­ществует до тех пор, пока исполняется функция. Это означает, что копия может выполнять опе­рации, которые потребуют вызова деструктора для уничтожения этой копии. Например, копия может резервировать память, которую необходимо освободить при ее уничтожении. По этой причине при уничтожении копии необходимо вызывать деструктор.

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

По умолчанию при создании копии объекта появляется его побитовая копия. Это означает, что новый объект служит точным дубликатом оригинала. Тот факт, что создается точная копия, может в некоторых случаях служить источником для беспокойства. Хотя для передачи объекта в функцию используется обычный механизм передачи по значению, который в теории защищает и изолирует вызываемый аргумент, остается возможность побочных эффектов, в результате кото­рых может быть поврежден объект, используемый как аргумент. Например, если некоторый объект, используемый как аргумент, резервирует память и освобождает эту память при своем уничтоже­нии, тогда его локальная копия внутри функции освободит ту же самую память при вызове де­структора. В результате исходный объект окажется поврежденным и по существу бесполезным. Можно предотвратить возникновение подобных проблем с помощью определения оператора копирования для собственного класса путем создания специ­ального типа конструктора, который называется конструктором копирования.