yandex rtb 1
ГоловнаЗворотній зв'язок
yande share

Объектно-ориентированное программирование

Лекция 5.

Статические члены класса. Конструкторы.

 

Статические переменные создаются один раз при запуске программы и разрушаются при завершении программы. Членам класса также могут быть статические переменные. Такая переменная создается только один раз, и все объекты данного класса используют этот экземпляр переменной.

Обратиться к статической переменной можно с помощью операции точка с использованием любого объекта данного класса. Однако этот способ не является предпочтительным. Более удобным является доступ с помощью операции разрешения видимости:

Имя_класса::идентификатор_статической_переменной

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

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

Рассмотрим программу, использующую статические переменные и методы класса.

 

#include <iostream.h>

class pair {

private:

  int first;

  char second;

  static int count;

public:

  bool compare(pair c);

  void setfirst(int first);

  void setsecond(char second);

  int getfirst() { return first;}

  char getsecond() {return second;}

  static void inccount() {count++;}

  static void deccount() {count--;}

  static int getcount();

};

bool pair::compare(pair c) {

              return (first==c.first && second==c.second);

  }

void pair::setfirst(int first) {

  pair::first=first;

}

void pair::setsecond(char second) {

  pair::second=second;

}

int pair::getcount() {

  return count;}

int pair::count=0;

void main() {

  pair a,b;

  a.setfirst(0);

  a.setsecond('a');

  pair::inccount();

  cout <<pair::getcount()<<endl;

  b.setfirst(1);

  b.setsecond('b');

  pair::inccount();

  cout <<pair::getcount()<<endl;

}

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

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

В языке C++ конструкторы определяются так же, как и любые другие функции за исключением двух моментов:

-          конструктор должен иметь то же имя, что и сам класс

-          конструктор не может возвращать значение. Более того, в прототипе или заголовке определения конструктора никакой тип (даже void) не указывается.

В следующем примере продемонстрирован конструктор, который выполняет следующие действия:

-          выделяет память под строку символов

-          присваивает начальные значения переменным – членам класса

-          увеличивает счетчик числа экземпляров класса на 1.

Кроме того, в программе продемонстрирована работа деструктора, назначение и описание которого будет рассмотрено позже.

 

#include <iostream.h>

#include <cstring>

class s_pair {

private:

  int first;

  char* second;

  static int count;

public:

  s_pair(int first, char* string);

  ~s_pair();

  void setfirst(int first) {s_pair::first=first;}

  int getfirst() { return first;}

  void setsecond(char* string) {

              int len=strlen(string);

              delete [] second;

              second=new char[len+1];

              strcpy(second,string);

  }

  char* getsecond() {

              char* str=new char[strlen(second)+1];

              strcpy(str,second);

              return str;

  }

  static int getcount() {return count;}

};

int s_pair::count=0;

s_pair::s_pair(int first,char* string) {

  s_pair::first=first;       

   int len=strlen(string);

  second=new char[len+1];

  strcpy(second,string);

  count++;

}

s_pair::~s_pair() {

  count--;

  delete [] second;

}

 

void main() {

  s_pair a(0,"it is string"), *b;

  cout <<a.getfirst()<<" "<<a.getsecond()<<endl<<"count="<<s_pair::getcount()<<endl;

  b=new s_pair(1,"it is outher string");

  cout<<b->getfirst()<<" "<<b->getsecond()<<endl<<"count="<<s_pair::getcount()<<endl;

  delete b;

  cout <<"count="<<s_pair::getcount()<<endl;

}

 

Вывод этой программы:

0 it is string

count=1

1 it is outher string

count=2

count=1

Существует специальный синтаксис для инициализации полей объекта с помощью конструктора. Инициализаторы конструктора для членов класса могут быть заданы через запятую в списке, который идет после двоеточия за списком параметров и предшествует телу. При применении инициализатора наш конструктор примет вид:

s_pair::s_pair(int first,char* string) : first(first){

  int len=strlen(string);

  second=new char[len+1];

  strcpy(second,string);

  count++;

}

При использовании инициализатора отпала необходимость в присваивании. Заметим, что инициализация, если она возможна, предпочтительней присваивания.

Для одного класса может быть определено несколько конструкторов. Все они должны иметь одно и то же имя, совпадающее с именем класса и различаться в аргументах. С++ предоставляет такую возможность, используя перегрузку функций. Определение нескольких функций с одним именем называется перегрузкой имени функции. При перегрузке функции различные определения должны либо содержать разное количество параметров, либо иметь различия в типах параметров. При обращении к функции компилятор использует то определение функции, количество и тип формальных параметров которого совпадают с количеством и типом аргументов в обращении функции.

 

7