Как мы знаем, все фундаментальные типы данных, или лучше сказать определенный с помощью этих типов объекты (переменные), характеризуются во-первых, количеством байт отводимых под объект, а во-вторых множеством операций определённых над объектом. Иногда, множество операций над объектами называют «поведением» объекта.
По аналогии с фундаментальными типами данных, с помощью ключевых слов struct, class, union, строятся структурированные (определённые программистом) типы данных, которые также характеризуются этими двумя признаками: объемом памяти и поведением. Как мы знаем объем занимаемый, структурированным объектом зависит от количества компонентных данных включённых в определение структурированного типа, а вот поведение объекта реализуется с помощью так называемых компонентных функций, описание или определение которых также должно присутствовать в определении структурированного объекта. В общем случае определение структурированного объекта, который содержит и компонентные данные, и компонентные функции выглядит следующим образом
struct имя_нового_типа {
определение компонентного данного_1;
…
определение компонентного данного _N;
определение или описание компонентной функции_1;
…
определение или описание компонентной функции_K;
};
Приведём конкретный пример определения структурированного типа, например, комплексное число, в котором поведение объекта (множество операций) реализуем с помощью набора компонентных функций. По мере того как будет меняться наше представление о правильном стиле реализации структурированных объектов, мы будем переделывать определение структурированного типа комплексное число, взятого нами в качестве примера.
struct comp {
// Компонентные данные
double Re, Im;
//Компонентные функции
comp (){Re= 0; Im= 0;} //Конструктор по умолчанию
comp(double r, double i) {Re = r; Im = i;} //Конструктор
comp(comp &T) { Re= T.Re; Im = T.Im;} // Конструктор копии
comp(double r) {Re = r; Im=0;} // Конструктор преобразования типа
~comp(){} // Деструктор
void display (){ cout<< “\n Re =”<< Re<<”\t Im = “<<Im;}
};
Существует два способа определения компонентных функций структурированного объекта. Первый способ – это записать определение функций непосредственно в определении структурированного типа, как и сделано в примере, в этом случае компилятор пытается сделать эти функции inline, т.е. так называемыми встраиваемыми функциями. Как мы знаем, функция может стать inline функцией, если её определение удовлетворяет достаточно жёсткому набору требований, например, определение не должно содержать операторы цикла, переключатели или операции перехода. Другими словами компонентную функцию можно определить прямо в определении структурированного типа, если она очень проста (в противном случае компилятор выдаст ошибку), если нет, если функция достаточно сложная, то существует второй способ определения компонентной функции. Он заключается в том, что в определении типа остаётся только описание функции, а её определение размещается за его пределами. Покажем это на примере конструктора по умолчанию comp () и функции display ().
Кроме того добавим в класс comp статическое поле static int count и модифицируем конструкторы и деструктор так, чтобы в этом поле хранилось текущее на данный момент число объектов типа comp. Добавим также статическую функцию GetCountComp(), которая при вызове возвращает значение count.
struct comp {
// Компонентные данные
double Re, Im;
static int count;
//Компонентные функции
comp (); //Описание комп. функции (конструктора по умолчанию)
comp(double r, double i) {Re = r; Im = i; count++;} //Конструктор
comp(comp &T) { Re= T.Re; Im = T.Im; count++;} // Конструктор копии
comp(double r) {Re = r; Im=0; count++;} // Конструктор преобразования типа
~comp(){count--;} // Деструктор
void display(); //Описание компонентной функции display()
static int GetCountComp(){return count; }
};
int comp::count = 0; //Инициализация статического компонентного данного
//-----------------------------------------------------------------------------------------------------
// Определение компонентной функции (конструктора по умолчанию)
comp::comp(){Re= 0; Im= 0; count++;}
//-----------------------------------------------------------------------------------------------------
A.display()
D.display();
// Определение компонентной функции display
void comp::display(){ cout<<“\n Re=”<< Re<<”\t Im=“<< Im;}
//-----------------------------------------------------------------------------------------------------------
//Определение обычной (не компонентной) функции sum()
comp sum(comp A, comp& С){
comp D;
D.Re = A.Re +С.Re;
D.Im = A.Im +С.Im;
return D;
}
Как видно из примера, определение компонентной функции display() ничем не отличается от определения обычной функции sum(), за исключением того, что перед именем функции стоит имя типа с двумя двоеточиями (comp::). Это «приставка» и сообщает компилятору, что функция display() является компонентной функцией класса comp.
Функция sum() – это обычная (не компонентная) функция, которая принимает в качестве параметров объект и ссылку на объект типа comp и возвращает объект типа comp. Как видно из текста, эта функция в точку вызова возвращает комплексное число, равное сумме двух комплексных чисел, переданных ей в качестве формальных параметров.
Способы вызова компонентных функций. Компонентные функции могут быть вызваны с помощью тех же самых операций:






