Static-члены (данные) класса

Компоненты-данные могут быть объявлены с модификатором класса памяти static. Класс, содержащий static компоненты-данные, объявляется как глобальный (локальные классы не могут иметь статических членов). Static-компонента совместно используется всеми объектами этого класса и хранится в одном месте. Статическая компонента глобального класса должна быть явно определена в контексте файла. Использование статических компонент-данных класса продемонстрируем на примере программы, выполняющей поиск введенного символа в строке.

#include "string.h"

#include "iostream.h"

enum boolean {fls,tru};

Class cls

{ char *s;

public:

static int k; // объявление static-члена в объявлении класса

static boolean ind;

void inpt(char *,char);

void print(char);

};

int cls::k=0; // явное определение static-члена в контексте файла

boolean cls::ind;

void cls::inpt(char *ss,char c)

{ int kl; // длина строки

cin >> kl;

ss=new char[kl]; // выделение блока памяти под строку

cout << "введите строку\n";

cin >> ss;

for (int i=0; *(ss+i);i++)

if(*(ss+i)==c) k++; // подсчет числа встреч буквы в строке

if (k) ind=tru; // ind==tru - признак того, что буква есть в строке

delete [] ss; // освобождение указателя на строку

}

void cls::print(char c)

{ cout << "\n число встреч символа "<< c <<"в строках = " << k;

}

void main()

{ cls c1,c2;

char c;

char *s;

cls::ind=fls;

cout << "введите символ для поиска в строках";

cin >> c;

c1.inpt(s,c);

c2.inpt(s,c);

if(cls::ind) c1.print(c);

else cout << "\n символ не найден";

}

Объявление статических компонент-данных задает их имена и тип, но не инициализирует значениями. Присваивание им некоторых значений выполняется в программе (вне объекта).

В функции main() использована возможная форма обращения к static-компоненте

cls::ind (имя класса :: идентификатор),

которая обеспечивается тем, что идентификатор имеет видимость public. Это дальнейшее использование оператора разрешения контекста “::”.

Отметим основные правила использования статических компонент:

- статические компоненты будут одними для всех объектов данного класса. То есть ими используется одна область памяти;

- статические компоненты не являются частью объектов класса;

- объявление статических компонент-данных в классе не является их описанием. Они должны быть явно описаны в контексте файла;

- локальный класс не может иметь статических компонент;

- к статической компоненте st класса cls можно обращаться cls::st, независимо от объектов этого класса, а также используя операторы . и -> при использовании объектов этого класса;

- статическая компонента существует даже при отсутствии объектов этого класса;

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

Указатель this

Как отмечалось выше, если некоторая функция является компонентой объекта, то при вызове этой функции к компонентам-данным этого объекта можно обращаться по имени (опуская имя объекта). Например, пусть имеется объявление двух объектов:

my_class ob1,ob2;

Вызовы компонент-функций имеют вид:

ob1.fun_1();

ob2.fun_2();

Пусть в обеих функциях содержится инструкция:

cout << str;

При объявлении двух объектов создаются две компоненты-данные str. Возникает вопрос, откуда каждая из двух функций узнает, с какой из компонент ей работать (точнее, где она расположена). Ответ состоит в следующем. В памяти для каждого располагаемого объекта создается скрытый указатель, адресующий начало выделенной под объект области памяти. Получить значение этого указателя в компонентах-функциях можно посредством ключевого слова this. Для любой функции, принадлежащей классу my_class, указатель this неявно объявлен так:

my_class *const this;

Таким образом, при объявлении объектов ob1 и ob2 создаются два this- указателя на эти объекты. Следовательно, любая функция, являющаяся компонентой некоторого объекта, при вызове получает this-указатель на этот объект. И приведенная выше инструкция в функции воспринимается как

cout << this->str;

Однако эта форма записи избыточна. С другой стороны, явное использование указателя this эффективно при решении некоторых задач.

Рассмотрим пример использования this-указателя на примере упорядочивания чисел в массиве.

#include<stdio.h>

#include<iostream.h>

class m_cl

{ int a[3];

public:

m_cl srt(); // функция упорядочивания информации в массиве

m_cl *inpt(); // функция ввода чисел в массив

void out(); // вывод информации о результате сортировки

};

m_cl m_cl::srt() // функция сортировки

{ for(int i=0;i<2;i++)

for(int j=i;j<3;j++)

if (a[i]>a[j]) {a[i]=a[i]+a[j]; a[j]=a[i]-a[j]; a[i]=a[i]-a[j];}

return *this; // возврат содержимого объекта, на который

} // указывает указатель this

m_cl * m_cl::inpt() // функция ввода

{ for(int i=0;i<3;i++)

cin >> a[i];

return this; // возврат скрытого указателя this

} // (адреса начала объекта)

void m_cl::out()

{ cout << '\n';

for(int i=0;i<3;i++)

cout << a[i] << ' ';

}

main()

{ m_cl o1,o2; // описание двух объектов класса m_cl

o1.inpt()->srt().out(); // вызов компонент-функций первого объекта

o2.inpt()->srt().out(); // вызов компонент-функций второго объекта

return 1;

}

Вызов компонент-функций для каждого из созданных объектов осуществляется:

o1.inpt()->srt().out;

Приведенная инструкция интерпретируется следующим образом:

сначала вызывается функция inpt для ввода информации в массив данных объекта о1;

функция inpt возвращает адрес памяти, где расположен объект о1;

далее вызывается функция сортировки информации в массиве, возвращающая содержимое объекта о1;

после этого вызывается функция вывода информации.

Ниже приведен текст еще одной программы, использующей указатель this. В ней выполняется добавление строки-компоненты одного объекта к строке-компоненте другого.

#include<iostream.h>

#include<string.h>

class B; // предварительное объявление класса В

Class A

{ char *s;

public:

A(char *s) // конструктор с параметром char*

{ this->s=new char[strlen(s)+1]; // память под строку-компоненту

strcpy(this->s,s);// копирование строки-аргумента в строку-компоненту

}

~A(){delete [] this->s;}

void pos_str(char *);

};

Class B

{ char *ss;

public:

B(char *ss) // конструктор с параметром char*

{ this->ss=new char[strlen(ss)+1]; // память под строку-компоненту

strcpy(this->ss,ss); // копирование строки-аргумента в

} // строку-компоненту

~B(){delete [] this->ss;}

char *f_this(void){return this->ss;}

};

void A::pos_str(char *s)

{ char *dd;

int i,ii;

dd=new char[strlen(this->s)+strlen(s)+2]; //память для перезаписи 2 строк

strcpy(dd,this->s); // перезапись в dd строки объекта a1

dd[strlen(this->s)]=' '; // удаление ’\0’

ii=strlen(this->s);

for(i=0;*(s+i);i++) // дозапись в dd строки объекта b1

*(dd+ii+i+1)=*(s+i);

*(dd+ii+i+1)=0;

delete [] this->s; // удаление строки объекта a1

this->s=dd; // перенаправление указателя на строку dd

cout << this->s << endl;

}

void main(void)

{ A a1("aa bcc dd ee");

B b1("bd");

a1.pos_str(b1.f_this());

}

В результате выполнения программы получим:

aa bcc dd ee bd

Отметим основные правила использования this-указателей:

- каждому объявляемому объекту соответствует свой скрытый this- указатель;

- this-указатель может быть использован только для нестатической функции;

- this указывает на начало своего объекта в памяти;

- this не надо дополнительно объявлять;

- this передается как скрытый аргумент во все нестатические (не имеющие спецификатора static) компоненты-функции своего объекта;

- указатель this - локальная переменная и недоступна за пределами объекта;

- обращаться к скрытому указателю можно this или *this.

Наши рекомендации