- •Глава 12
- •Конструкторы и деструкторы. Список инициализации элементов
- •Конструкторы по умолчанию и конструкторы копирования
- •Указатель this
- •Встраиваемые (inline-) функции
- •Статические члены класса
- •Использование указателей на функции-члены класса
- •Массивы объектов класса
- •Дружественные функции и друзья класса
- •Глава 13
- •Множественное наследование
- •Виртуальные базовые классы
- •Глава 14
- •Перегрузка функций
- •Перегрузка конструкторов
- •Создание и использование конструкторов копирования
- •Определение адреса перегруженной функции
Указатель this
Каждый объект в C++ содержит специальный указатель с именем this, который автоматически создается самим компилятором и указывает на данный объект. Типом this является Т*, где T — тип класса данного объекта. Поскольку указатель this определен в классе, область его действия — класс, в котором он определен. Фактически this является скрытым параметром класса, добавляемым самим компилятором к его определению. При вызове обычной функции-члена класса ей передается указатель this так, как если бы он был первым аргументом. Таким образом, вызов функции-члена
ObjName.FuncName(par1, par2);
компилятор трактует так:
ObjName.FuncName(&ОbjName, parl, par2);
Но, поскольку аргументы помещаются в стек справа налево, указатель this помещается в него последним. В теле функции-члена адрес объекта доступен как указатель this. Дружественным функциям и статическим функциям-членам класса (о них мы будем говорить позже) указатель this не передается. Нижеследующий пример демонстрирует использование этого указателя:
#include <iostream.h>
#include <string.h>
class Т
{
public:
Т(char*);
void Greeting();
char item[20];
};
Т::Т(char* name)
{
strcpy(item, name);
Greeting(); //Bee три
this->Greeting() ; //оператора
(*this) .Greeting(); //эквивалентны
}
void
T: :Greeting()
{
//Оба нижеследующих оператора эквивалентны
cout «"Hello, " « item « "\n";
cout «"Hello, " « this->item « "\n";
}
int main()
{
Т ob(“dear.”) ;
return 0;
}
Как можно видеть, внутри конструктора класса и функции-члена Greeting() обращения к данным-членам класса и функциям-членам могут осуществляться как непосредственно по имени, так и с помощью указателя this. Поэтому на практике такое употребление указателя this встречается крайне редко. В основном указатель this используется для возврата указателя (в форме: return this;) или ссылки (в форме: return *this;) на соответствующий объект. Этот указатель находит широкое применение при перегрузке операторов.
Встраиваемые (inline-) функции
В C++ можно задать функцию, которая, фактически, не вызывается, а ее тело встраивается в программу в месте ее вызова. Она действует почти так же, как макроопределение с параметрами. По сравнению с обычными функциями встраиваемые (in-line) функции обладают тем преимуществом, что их вызов не связан с передачей аргументов и возвратом результатов через стек и, следовательно, они выполняются быстрее обычных. Недостатком встраиваемых функций является то, что если они слишком большие и вызываются слишком часто, объем программы сильно возрастает. Из-за этого применение встраиваемых функций обычно ограничивается только очень простыми функциями.
Объявление встраиваемой функции осуществляется с помощью спецификатора inline, который вписывается перед определением функции.
Следует иметь в виду, что спецификатор inline только формулирует требование компилятору сформировать встроенную функцию. Если компилятор не в состоянии выполнить это требование, функция компилируется как обычная. Компилятор не может сгенерировать функцию как встраиваемую, если она:
• содержит оператор цикла (for, while, do-while);
• содержит оператор switch или goto;
• содержит статическую переменную (static);
• если функция является рекурсивной;
• имеет возвращаемый тип, отличный от void, и не содержит оператора return;
• содержит встроенный код ассемблера.
Компилятор может налагать и другие ограничения на использование inline-функций. Уточните их в описании конкретного компилятора. Ниже приведен пример использования встраиваемой функции:
#include <iostream.h>
inline int even(int x)
{
return !(x%2);
}
int main()
{
int n;
cin » n;
if (even(n))
cout « n « "является четным\n";
else
cout « n « " является нечетным \n";
return 0;
}
В этом примере программа читает введенное целое число и сообщает, является ли оно четным. Функция even () объявлена как встраиваемая. Это означает, что оператор
if (even(n))
cout « n «”является четным\n”
эквивалентен следующему:
if (!(n%2))
cout « n « "является четным\n";
Важно отметить, что встраиваемая функция должна быть не только объявлена, но и определена до ее первого вызова. Поэтому определение inline-функций обычно размещается в заголовочном файле. В приведенном выше примере функция even() была определена до функции main (), в которой она используется.
Встроенными могут быть объявлены не только обычные функции, но и функции-члены. Для этого достаточно включить ее определение в объявление класса (в этом случае ключевое слово inline больше не нужно) или перед определением функции вставить ключевое слово inline.
Следующий пример демонстрирует использование встроенных функций-членов.
class Point
{
int x;
int у;
public:
int GetX() {return x;} //inline-функция
int GetY() {return у;} //inline-функция
void SetX(int _x){x =_x;} //inline-функция
void SetY(int _y){y =_y;} //inline-функция
};
Можно определить встроенную функцию-член и вне тела класса, предварив ее определение ключевым словом inline:
class Point
{
int x;
int y;
public:
int GetX() ;
int GetY() ;
void SetX(int);
void SetY(int);
};
inline int
Point::GetX()
{
return x;
}
inline int
Point::GetY()
{
return у;
}
void
Point::SetX(int _x)
{
x = _x;
}
void
Point::SetY(int _y)
{
у = _y;
}
