Пример: class x{
int m; public:
int readm () {return x :: m;} void setm (int m)
{x :: m = m;}
…
};
В функции x::setm() имя аргумента m скрывает элемент m, так что ссылаться на него можно только по уточненному имени x::m. Левым операндом (::) должно быть имя класса, если используется имя :: fun – это имя должно быть глобальным.
Наиболее часто такая запись применяется для того, чтобы использовать имена общеизвестных функций (printf, open) как имена функций-членов.
Пример: class my_file
{
…
public:
int open (char *, char *);
}
int my_file :: open (char * name, char * spee)
{
…
if (:: open (name, flag)) {…}
};
5. СТАТИСТИЧЕСКИЕ ЭЛЕМЕНТЫ КЛАССА
Класс – это тип, а не объект данных. Для каждого объекта в классе существует своя копия элементов класса, но часто бывает необходимо, чтобы все объекты одного класса совместно пользовались одними данными. Это можно осуществить, используя глобальную переменную. Но иногда желательно объявить совместно используемые данные частью класса (обеспечить санкционированный доступ). Этого можно достигнуть, объявив соответствующие данные статистическими элементами класса.
16
Пример: реализации списка всех задач. class task
{
…
task *next;
static task *task_chain; void schedule (int); void wait (event);
…
};
Описание task_chain как статического элемента обеспечивает условие, что цепочка задач будет всего одна, а не по одной копии на каждый объект task. Переменная находится в области действия класса task, обратиться извне к ней нельзя (только объявив как public).
Использование статических объектов сокращает потребность глобальных переменных.
6. ПОДСТАВЛЯЕМЫЕ ИЛИ INLINE-ФУНКЦИИ
Причина введения таких функций состоит в повышении эффективности работы программы. «Стоимость» вызова коротких, часто встречающихся функций высока, так как необходимо затратить память под переменные, передачу параметров в стэк и т. д. Такие функции объявляют подставляемыми. inline intif (void)
{…}
Для такой функции компилятор сгенерирует код в месте ее вызова. При использовании подставляемых функций возрастает скорость выполнения программ, но увеличиваются программный код и время на компиляцию.
Пример:
#include <iostream.h> class cl
{
int i;
public: intget_i (void); intput_i (int j);
};
17
inline int cl :: get_i (void)
{
return i;
}
inline void cl :: put_i (int j)
{
i=j;
}
main (void)
{
cl s; s.put_i (10);
cout<<s.get_i ();
}
Ситуации, препятствующие inline кода:
–наличие оператора switch, goto, операторов цикла, в случае, если функция возвращает более одного значения;
–inline-функции не могут быть рекурсивными (вызывать сами себя) и содержать статические переменные;
–inline-функции могут быть членами класса, могут быть обычными функциями.
Любая функция, определенная внутри шаблона класса, автоматически делается inline-функцией.
Пример:
#include <iostream.h> class cl
{
int i; public:
int get_i (void) { return i; }
intput_i (int j) {i=j; return i;}
};
18
7. ДИНАМИЧЕСКОЕ ВЫДЕЛЕНИЕ ПАМЯТИ.
ОПЕРАТОРЫ NEW, DELETE
Синтаксис: pointer_var=new type_var; delete pointer_var;
где pointer_var – указатель на переменную type_var.
Оператор new выделяет место для переменной в соответствующей области памяти и возвращает адрес выделенного места в случае успеха и NULL – если произошла ошибка. Оператор new сам определяет размер типа type_var и возвращает указатель, преобразованный к этому типу.
Выделение памяти под массив: pointer_var=new type_var [SIZE] delete [SIZE] pointer_var;
SIZE можно опустить, компилятор знает объем выделенной памяти. Пример:
main (void)
{
int *p; p=new int; if (!p)
{
cout<<”Памяти недостаточно\n”; return 1;
}
….
*p=20;
cout<<p; delete p; return 0;
}
Динамически можно выделить память под объект любого определенного к этому моменту типа. Динамическое выделение памяти под одиночные переменные невыгодно, так как расходуется память и под саму информацию о ее выделении. Целесообразно динамически выделять память под массивы больших размеров или под массивы, размерность которых определяется в процессе выполнения программы. Это обычно делается в конструкторе класса.
19
Пример:
#include <iostream.h> main (void)
{
int *p; unsigned int size;
cout <<"Введите длину массива ;" cin >> size;
p=new int [SIZE]; if (! p){
cout<< “Недостаточно памяти;” return 1;
}
for (int i=0; i<size; i++){ p[i] _i *i; cout<<p[i];
}
delete p;
}
8. ПЕРЕГРУЖЕННЫЕ ФУНКЦИИ OVERLOADING
Возможность создания перегруженных функций в С++ является одним из способов реализации полиморфизма. Две или более функций могут иметь одно и то же имя и отличаться количеством или типом параметров. Обычно перегруженные функции используются для реализации похожих действий над данными разного типа.
В С есть стандартные функции преобразования строки в число типа int, float, long (atoi, atof, atoll). В С++ есть аналог этих функций – перегруженная функция atonum для всех типов числовых данных.
Пример:
#include <iostream.h> int sqr_it (int i);
float sqr_it (float d); long sqr_it (long l);
20