- •Глава 12
- •Конструкторы и деструкторы. Список инициализации элементов
- •Конструкторы по умолчанию и конструкторы копирования
- •Указатель this
- •Встраиваемые (inline-) функции
- •Статические члены класса
- •Использование указателей на функции-члены класса
- •Массивы объектов класса
- •Дружественные функции и друзья класса
- •Глава 13
- •Множественное наследование
- •Виртуальные базовые классы
- •Глава 14
- •Перегрузка функций
- •Перегрузка конструкторов
- •Создание и использование конструкторов копирования
- •Определение адреса перегруженной функции
Использование указателей на функции-члены класса
Можно определить указатель на функцию-член класса. Синтаксис определения следующий:
<возвр_тип>
(<имя_класса>: : *<имя_указателя>) (<параметры>) ;
Например:
void (Т::*funcPtr)(int х, int у);
Таким образом, синтаксис определения указателя на функцию-член класса отличается от объявления указателя на обычную функцию тем, что в круглых скобках указывается имя класса, отделенное от имени указателя символом расширения области видимости, а само имя указателя предваряется звездочкой. Эта звездочка должна напомнить программисту, что при использовании такой указатель должен разыменовываться (в отличие от указателя на обычную функцию). Например,
this->*funcPtr(x,y);
или
*this.* funcPtr(x,y);
Указателю на функцию-член класса передается скрытый указатель this (иначе ему нельзя было бы присвоить значение адреса некоторой функции-члена класса).
Следующий пример демонстрирует использование указателей на функцию-член.
class Т
{
int i;
public:
Т (int _I) : i (_i) { }
void MembFunc() {printf ("Hello! ") ; }
void CallMembFunc(void (T::*funcPtr)() }
{
this->*funcPtr)();
}
};
int main()
{
void (T::*funcPtr)() = &T::MembFunc;
Т ob(2000);
ob.CallMembFunc(funcPtr) ;
return 0;
}
C++ накладывает определенные ограничения на использование указателей на функции-члены класса:
• указатель на функцию-член класса не может ссылаться на статическую функцию-член класса (так как ей не передается указатель this);
• указатель на функцию-член класса не может быть преобразован в указатель на обычную функцию, не являющуюся членом какого-нибудь класса (по той же причине).
Массивы объектов класса
Из объектов класса, как и из обычных переменных, можно строить массивы. Синтаксис объявления массива объектов аналогичен синтаксису объявления массивов обычных переменных. Например, следующее объявление создает массив из 10 элементов, которые являются объектами класса AnyClass:
AnyClass obArr[10];
Однако для того, чтобы компилятор смог создать этот массив, он должен использовать конструктор по умолчанию объектов класса. В отношении конструктора по умолчанию действуют перечисленные нами ранее правила. Рекомендуем не полагаться на то, что компилятор сам создаст конструктор по умолчанию, и всегда при объявлении массива объектов некоторого класса включать в этот класс конструктор по умолчанию.
Доступ к элементам массива также аналогичен доступу к массивам переменных любого другого типа. Например,
#include <iostream.h>
class AnyClass
{
int a;
public:
AnyClass(int n) {a = n;}
int GetA()(return a;}
};
main ()
{
//Объявление и инициализация массива объектов
AnyClass obArr[5] = {13, 17, 21, 23, 27};
int i;
for (i=0; i<4; i++)
{
//Обращение к элементам массива
cout « obArr[i].GetA() « ' ' ;
}
cout « "\n";
return 0;
}
Эта программа выводит на экран проинициализированные значения массива объектов obАrr. Фактически, примененный здесь синтаксис инициализации массива является сокращенной формой следующей конструкции:
AnyClass obArr[5] = {AnyClass(13),
AnyClass(17),
AnyClass(21) ,
AnyClass(23),
AnyClass(27)};
К сожалению, ею можно воспользоваться только при инициализации массивов объектов, конструктор которых содержит только один параметр. При инициализации массивов объектов с конструктором, содержащим несколько параметров, приходится использовать полную (или длинную) форму конструкции. В следующем примере создается двумерный массив объектов, конструктор которого содержит два параметра.
#include <iostream.h>
class Coord
{
int x, у;
public:
Coord(int _x, int _y) {x = _x; у = _y;}
int GetX(){return x;}
int GetY(){return y;}
};
main()
{
Coord coordArr[4][2] = {Coord(3,4), Coord(5,6), Coord(7,8), Coord(9,10), Coord(11,12), Coord(13,14), Coord(15,16), Coord(17,18),
};
int i, j;
for (i=0; i<4; i++)
for (j=0; j<2; j++)
{
cout « coordArr[i][j].GetX() « ' ' ;
cout « coordArr[i][j].GetY() « ' ' ;
}
cout « "\n";
return 0;
}
Использование указателей для доступа к объектам массива совершенно аналогично их использованию для обычных переменных и структур. Арифметика указателей также аналогична. Инкрементирование указателя приводит к тому, что он указывает на следующий объект массива, декрементирование — к тому, что он указывает на предыдущий объект массива. Рассмотрим пример:
#include <iostream.h>
class Coord
{
int x, у;
public:
Coord(int _x, int _y) {x = _x; у = _y;}
int GetX(){return x;}
int GetY(){return y;}
};
main()
{
Coord obArr[4] = {
Coord(3,4), Coord(5,6), Coord(7,8), Coord(9,10), Coord(11,12), Coord(13,14), Coord(15,16), Coord(17,18)
};
int i;
Coord* ptr;
ptr = obArr; //Инициализация указателя адресом массива
for (i=0; i<4; i++)
{
cout « ptr->GetX() « ' ';
cout « ptr->GetY() « "\n";
ptr++; //Переход на следующий объект
}
cout « "\n";
return 0;
}
Эта программа выводит на экран в каждой строке значения переменных х и у текущего элемента массива объектов.
Массивы объектов классов могут располагаться в куче. Например:
#include <iostream.h>
class Coord
{
int х, у;
public:
Coord(int _x, int _y){x = _х; у = _у;}
Coord(){x = 0; у = 0;}
int GetX(){return x;}
int GetY(){return y;}
};
main()
{
int i;
Coord* ptr;
//Создание массива объектов в куче
ptr = new Coord[6];
for (i=0; i<6; i++)
{
cout « ptr->GetX() « ' ';
cout « ptr->GetY() « "\n";
ptr++; //Переход на. следующий объект
}
cout « "\n";
//Удаление массива объектов из кучи
delete[] ptr;
return 0;
}
Следует обратить внимание, что для удаления массива объектов используется форма оператора delete с квадратными скобками.
