Статические переменные-члены и статические функции-члены.
До этого момента предполагалось, что все данные находящиеся в классе должны принадлежать объектам класса, причём какое-либо данное должно было принадлежать конкретному объекту класса. Но иногда возникает необходимость в получении информации о накоплении данных программой. (например о количестве объектов класса). Эту задачу решают статистические переменные-члены. Эти переменные используются всеми объектами класса, то есть можно сказать, что они принадлежат классу, а не объекту класса. Их можно рассматривать как нечто среднее между глобальными переменными и переменными-членами.
#include<iostream.h>
class Cat
{
public:
Cat(int age):itsAge(age){HayMenyCats++;}
virtual ~Cat(){HayMenyCats--;}
virtual int GetAge() {return itsAge;}
virtual void SetAge(int age){itsAge=age;}
static int HayMenyCats;
private:
int itsAge;
};
int Cat::HayMenyCats =0;
int main(void)
{
const int MaxCat=5;
int i;
Cat *CatHouse[MaxCat];
for(i=0;i<MaxCat;i++)
CatHouse[i]=new Cat(Maxcat-i);
for(i=0;i<MaxCat;i++)
{
cout<<"сейчас у нас ";
cout<<Cat::HayMenyCats;
cout<<" кота.\n";
cout<<"удалим кота, возраст которого ";
cout<<CatHouse[i]->GetAge()<<" года \n";
delete CatHouse[i];
CatHouse[i]=0;
}
return 0;
}
у нас живёт 4 кота .
удалим кота, возраст которого 4 года
у нас живёт 3 кота .
удалим кота, возраст которого 3 года
у нас живёт 2 кота .
удалим кота, возраст которого 2 года
у нас живёт 1 кота .
удалим кота, возраст которого 1 года
Рекомендуется:
- Применять статические переменные для совместного использования данных несколькими объектами класса.
- Необходимо ограничить доступ к статическим ,объявив их private или protected.
- Не используйте статические данные для хранения данных одного объекта. Эти переменные предназначены для обмены данными между объектами класса.
Статические функции-члены подобны статическим переменныи-членам. Их можно вызвать, в отличии от других функций-членов, тогда. Когда нет ни одного объекта данного класса.
#include<iostream.h>
class Cat
{
public:
Cat(int age) :itsAge(age) {HayMenyCats++;}
virtual ~Cat(){HayMenyCats--;}
virtual int GetAge() {return itsAge;}
virtual void SetAge(int age) {itsAge=age;}
static int GetHayMeny()
{ return HayMenyCats;}
private:
int itsAge;
static int HayMenyCats;
};
void Info();
int Cat::HayMenyCats =0;
int main(void)
{
const int MaxCat=4;
int i;
Cat *CatHouse[MaxCat];
for(i=0;i<MaxCat;i++)
{
CatHouse[i]=new Cat(MaxCat-i);
Info();
cout<<CatHouse[i]->GetAge()<<" года\n";
}
for(i=0;i<MaxCat;i++)
{ cout<<"удаляем старшего кота \n"<<endl;
delete CatHouse[i];
CatHouse[i]=0;
Info();
}
return 0;
}
void Info()
{
cout<< "у нас живёт "<< Cat::GetHayMeny()<<" кота .\n";
}
Вызов статических функций может быть двух видов:
- Cat::GetHayMeny() — без определения объекта, но с указанием класса.
- TheCat. GetHayMeny() —с определением объекта, и без указания класса.
Статические функции-члены не содержат указателя this. Поэтому они не могут использовать обычные нестатические переменные-члены, так как доступ к ним осуществляется через указатель this.
Шаблоны функций и классов
Шаблоны представляют ещё одну реализацию полиморфизма в программах С++. Они позволяют создать универсальный фрагмент кода, а затем использовать его многократно с различными типами данных или различными объектами. С помощью шаблонов можно уменьшить объём и сложность программы.
Шаблоны функций позволяют передавать в качестве аргумента тип переменной. Шаблоны создают семейства функций, определяющее неограниченное множество родственных функций. Экземпляризация— операция создания определённого типа из шаблона. Отдельные классы называются экземплярами шаблона. Параметризованные шаблоны — представляют возможность создания общего класса и для построения конкретных экземпляров передают этому классу в качестве параметров типы данных.
На пример список. Список может быть для чего угодно.
Построение шаблонов рассмотрим на примере. Необходимо написать функцию расчёта куба для аргумента. (Cub()).
#include<iostream.h>
#include<math.h>
template <class T>
T cub(T x)
{ return x*x*x;}
template <class SwapType>
void Swap(SwapType &x,SwapType &y)
{ SwapType tmp;
tmp=x;
x=y;
y=tmp;
}
template <class T1,class T2>
T1 max(T1 x,T2 y)
{
if(x>y)return x;
else return y;
}
void main(void)
{
int i=3;
float f=3.12;
double x=3.1e2;
cout<<"//целое "<<cub(i)<<endl;
cout<<"//вещественное "<<cub(f)<<endl;
cout<<"//двойной точности "<<cub(x)<<endl;
char ch1='a',ch2='z';
cout<<"//1-- "<<ch1<<" 2-- "<<ch2<<endl;
Swap(ch1,ch2); cout<<"//переставили "<<endl;
cout<<"//1-- "<<ch1<<" 2-- "<<ch2<<endl;
int c1=0,c2=9;
cout<<"//1-- "<<c1<<" 2-- "<<c2<<endl;
Swap(c1,c2); cout<<"//переставили "<<endl;
cout<<"//1-- "<<c1<<" 2-- "<<c2<<endl;
cout<<"//max из int "<<c1<<" и int "<<c2<<" = "<<max(c1,c2)<<endl;
cout<<"//max из char "<<ch1<<" и char "<<ch2<<" = "<<max(ch1,ch2)<<endl;
cout<<"//max из int "<<i<<" и float "<<f<<" = "<<max(f,i)<<endl;
}
//целое 27
//вещественное 30.3713
//двойной точности 2.9791e+07
//1-- a 2-- z
//переставили
//1-- z 2-- a
//1-- 0 2-- 9
//переставили
//1-- 9 2-- 0
//max из int 9 и int 0 = 9
//max из char z и char a = z
//max из int 3 и float 3.12 = 3.12
Шаблоны классов
Шаблон класса представляет собой скелет обобщённого класса. Ситаксис такой:
Template< список_аргументов_шаблона>
{
//тело класса
};
Каждый аргумент в списке является либо объявлением типа float a; либо идентификатором класса class T. Из-за этого определение функции-метода шаблонного класса имеет вид:
Template< список_аргументов_шаблона>
Тип_результата имя_класса < список_аргументов_шаблона>::
Имя_функции( список_аргументов_функции)
{
//тело функции.
}
объявление объекта шаблонногокласса:
имя_класса_шаблона < список_аргументов_шаблона> имя_объекта;
Пример использования шаблонов будем рассматривать на создании очереди.
Связные списки и другие структуры
Для работы с массивом необходимо знать его размерность, хотя бы в начале работы программы. Если это данное не известно то можно либо сильно увеличить резервируемую память, либо рисковать ограниченность пространства для данных в массиве. Данную проблему решают связные списки. Связанный список это структура данных, содержащая из взаимосвязанных блоков. Идея состоит в том, что бы создать класс, который поддерживал бы данные определённого типа, среди которых был бы указатель, связанный с другим объектом этого класса.
Существуют три основных вида списков:
- Однонаправленные списки (очередь, стек);
- Двунаправленные списки (дек и т.д.);
- Деревья.
Названия образуются от количества связующих список указателей в каждом объекте списка.
Список состоит из узлов, узлы представляют собой абстрактные классы. Начало — это начало обработки промежуточных узлов списка, которые отвечают за хранение данных, указатель узла - “хвост” обязательно имеет значение null (0).
// программа работы с динамическими списками при помощи классов.
// однонаправленные списки, двунаправленные списки и деревья.
#include <iostream.h>
#include <iomanip.h>
#include <fstream.h>
ofstream fout("rez.txt");
ifstream fin("rez.txt");
class Data
{
public:
Data ();
~Data(){delete fam;}
int Compare(const Data &);
void Show();
private:
char fam[25];
float ball;
};
Data::Data()
{
cout<<"\n Введите фамилию и средний балл :";
cin>>fam>>ball;
}
void Data::Show()
{ cout.width(25);
cout.fill(' ');
cout<<fam;
cout.width(10);
cout.fill('-');
cout.precision(3);
cout<<ball<<"\n";
fout.width(25);
fout.fill(' ');
fout<<fam;
fout.width(10);
fout.fill('-');
fout.precision(3);
fout<<ball<<"\n";
//fout<<fam<<"--"<<ball<<endl;
}
int Data::Compare(const Data &theO)
{
if(strcmp(fam,theO.fam)<0)return -1;
if(strcmp(fam,theO.fam)==0)return 0;
if(strcmp(fam,theO.fam)>0)return 1;
}
class Node;
class HeadNode;
class TailNode;
class InternalNode;
class Node
{public:
Node(){}
virtual ~Node(){}
virtual Node* Insert(Data* theData)=0;
virtual void Show()=0;
private:
};
class InternalNode:public Node
{public:
InternalNode(Data *theData, Node *next) ;
~InternalNode(){delete myNext,delete myData;}
virtual Node* Insert(Data *theData);
virtual void Show() {myData->Show();myNext->Show();}
private:
Data* myData;
Node* myNext;
};
InternalNode::InternalNode(Data *theData,Node*next):
myData(theData),myNext(next)
{}
Node* InternalNode ::Insert(Data *theData)
{
int result=myData->Compare(*theData);
switch(result)
{
case 0:
case1:{InternalNode *dataN=new InternalNode (theData,this);
return dataN;}
case-1:{myNext=myNext>Insert(theData);
return this;}
}
return this;
}
class TailNode:public Node
{
public:
TailNode(){}
~TailNode() {}
virtual Node* Insert(Data *theData);
virtual void Show(){ }
private:
};
Node* TailNode::Insert(Data *theData)
{
InternalNode *dataN=new InternalNode (theData,this);
return dataN;
}
class HeadNode:public Node
{public:
HeadNode(){myNext=new TailNode;};
~HeadNode(){delete myNext;}
virtual Node* Insert(Data *theData);
virtual void HeadNode::Show();
private:
Node* myNext;
};
void HeadNode::Show()
{
cout<<" Фамилия "<<" балл "<<endl;
fout<<" Фамилия "<<" балл "<<endl;
myNext->Show();
}
Node* HeadNode::Insert(Data *theData)
{
myNext=myNext>Insert(theData);
return this;
}
class Admin
{public:
Admin();
~Admin(){delete myHead;}
void Insert(Data* pData);
void ShowAll(){myHead->Show();}
private:
HeadNode* myHead;
};
Admin::Admin()
{
myHead=new HeadNode;
}
void Admin:: Insert(Data*pData)
{
myHead->Insert(pData);
}
int main()
{
Data* pData;
int val=1;
Admin ll;
while(val!=0)
{
pData=new Data();
ll.Insert(pData);
cout<<"хотите закончить ввод? Если да, то введите 0";
cin >>val;
}
ll.ShowAll();
cout<<"********************************\n";
fout.close();
return 0;
}