Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Организация исходных файлов

Встроенные функции-члены

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

class CRectangle{private:int Left;int Top;int Right;int Bottom; public:CRectangle ();CRectangle {int L, int T, int R, int B);void Draw (void);void GetCoord (int *L, int *T, int *R, int *B);void SetCoord (int L, int T, int R, int B}; };

При внешнем определении функции-члена перед ее именем нужно поставить имя класса с последующим оператором расширения области видимости «::».

#include <stdlib.h>

 

CRectangle::CRectangle () { Left = Top = Right = Bottom = 0;}CRectangle::CRectangle (int L, int T, int R, int B) {SetCoord (L,T,R,B); }void CRectangle::Draw (void) {Line (Left, Top, Right, Top);Line {Right, Top, Right, Bottom);Line (Right, Bottom, Left, Bottom);Line (Left, Bottom, Left, Top);

}

void CRectangle::GetCoord (int *L, int *T, int *R, int *B) {*L = Left; *T = Top; *R = Right; *B = Bottom; }void CRectangle::SetCoord (int L, int T, int R, int B) {L = _min (_max (0,L), 80);T = _min (_max (0,T), 25);R = _min (_max (0,R), 80);В = _min (_max (0,B), 25);R = _max (R,L);В = _max (B,T);Left = L; Top = T; Right = R; Bottom = B;}

Есть существенное различие между функцией, определенной внутри тела класса, и функцией, определенной вне класса. По умолчанию для последней не выполняется inline-подстановка (см. описание inline-функций в гл. 2). Следовательно, очень короткие функции можно определить внутри тела класса, а более длинные – вне его. Например, конструкторы класса CRrectangle и метод GetCoord (самые короткие) могут быть определены внутри класса, а функции Draw и SetCoord (самые длинные) – вне его. Полное определение класса CRectangle приведено в листинге 3.1 в конце следующего раздела.

Можно заставить компилятор рассматривать функцию, заданную вне определения класса, как встроенную, используя спецификатор inline, как было описано в гл. 2. Например, можно сделать функцию CRectangle::GetCoord встроенной, объявив ее внутри определения класса CRectangle,

void inline GetCoord (int *L, int *T, int *R, int *B);

а затем определить ее вне описания класса.

void inline CRectangle::GetCoord (int *L, int *T, int *R, int *B) {*L = Left; *T = Top; *R = Right; *B = Bottom; }

Если программа состоит из нескольких исходных файлов, написанных на языке C++, то определение класса обычно помещается вместе с определениями всех встроенных функций-членов внутри единого заголовочного файла (файла с расширением .h). Затем данный файл включается в любой исходный файл, в котором используется этот класс. Такая организация файлов гарантирует, что определение класса вместе с кодом любой встроенной функции будет доступно при обращении к классу или при вызовах его функций-членов. Как указывалось в гл. 2, компилятор должен иметь доступ к встроенной функции при каждом ее вызове.

Определения любых функций-членов, не являющихся встроенными, обычно также размещаются внутри отдельного файла, называемого файлом реализации класса. Скомпилированный вариант файла реализации необходимо скомпоновать с программой (например, путем включения файла реализации .срр в список файлов проекта Visual C++). Отметим: размещение определений не встроенных функций в файле заголовков вместо отдельного файла реализации приводит к ошибке компоновщика «повторное символическое определение» (symbol redefinition), если заголовочный файл включен более чем в один исходный файл.

Листинги 3.1 и 3.2 содержат полный исходный код последнего варианта класса CRectangle. Определение класса CRectangle помещено в файл с именем CRect.h (файл заголовков класса), а определения функций-членов, не являющихся встроенными, – в CRect.cpp (файл реализации класса).

Листинг 3.1

// CRect.h: файл заголовков CRectangleclass CRectangle{private:int Left; int Top; int Right; int Bottom;public:CRectangle (}{

Left = Top = Right = Bottom = 0;

} CRectangle (int L, int T, int R, int B){

SetCoord (L, T, R, B);

}void Draw (void); void GetCoord (int *L, int *T, int *R, int *B){

*L - Left;

*T = Top;

*R = Right;

*В = Bottom;

}void SetCoord (int L, int T, int R, int B); };

Листинг 3.2

// CRect.cpp: файл реализации#include "crect.h" #include <stdlib.h> void Line (int XI, int Yl, int X2, int Y2); void CRectangle::Draw (void) {Line (Left, Top, Right, Top);Line (Right, Top, Right, Bottom);Line (Right, Bottom, Left, Bottom);Line (Left, Bottom, Left, Top); }void CRectangle::SetCoord (int L, int T, int R, int B) {L = _min (_max (0,L), 80);T = _min (_max (0,T), 25);R = _min (_max (0,R), 80);В = _min (_max (0,B), 25);R = _max (R,L);В = _max (B,T);Left = L; Top = T; Right = R; Bottom = B;}

При создании класса CRectangle предполагалось, что функция Line определена в другом модуле. Файл CRect.h должен быть включен в любой файл, содержащий ссылку на класс CRectangle (включая CRect.cpp!), а скомпилированный вариант CRect.cpp должен быть скомпонован с программой.

3.8. Указатель this

При ссылке на переменные-члены класса из кода, находящегося вне класса, в выражении всегда указывается экземпляр класса. Следовательно, компилятор может определить, какая копия переменных-членов ему доступна. Предположим, например, что класс CTest содержит переменную N, тогда в приведенном ниже коде сначала будет напечатана копия переменной N объекта Test1, а затем – объекта *PTest2.

CTest Testl;CTest *PTest2 = new CTest;//...cout << Testl.N << '\n';cout << Test2->N << '\n';

При ссылке на переменную-член внутри функции-члена частный экземпляр класса не описывается.

class CTest {public: int N; int GetN () {

return N; // N возвращается БЕЗ точного указания объекта

}}

Как компилятор определяет, на какую копию переменной N ссылается метод класса? В действительности, компилятор передает методу класса скрытый указатель на объект. Функция использует именно этот скрытый указатель для доступа к корректной копии переменных-членов. Например, в вызове

Test.GetN ();

компилятор передает скрытый указатель GetN на объект Test. Функция GetN использует именно этот указатель для доступа к копии переменной N, принадлежащей объекту Test.

Можно непосредственно обратиться к скрытому указателю с использованием спецификатора this. Другими словами, внутри функции-члена this является предопределенным указателем, содержащим адрес объекта, на который ссылается функция (иногда называемого текущим объектом). Так функция GetN может быть описана следующим образом.

int GetN () {return this->N; // эквивалентно 'return N;' }

Имя функции-члена с выражением this-> перед ним является корректным, но не преследует ни какой цели, так как использование указателя this и так подразумевается в простой ссылке на переменную-член. Однако далее будет показано несколько практических применений указателя this.

Если нужно получить доступ к глобальным переменным или к функции, имеющей такое же имя, как переменная-член или функция-член, то перед именем необходимо поставить операцию расширения области видимости «::». Например:

int N = 0; // глобальная переменная Nclass CTest{public:int N; //переменная-член Nint Demo () {

cout <<::N << '\n'; // печать глобальной переменной N

cout << N << '\n'; // доступ к переменной-члену N

// с использованием указателя 'this'

} }
<== предыдущая лекция | следующая лекция ==>
Массивы объектов | Порядок вызова конструкторов и деструкторов
Поделиться с друзьями:


Дата добавления: 2014-01-07; Просмотров: 887; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.013 сек.