Специальные элементы класса
Поля, значения которых не меняются на протяжении всего времени существования объекта, рекомендуется описывать со спецификатором
const. Инициализировать такие поля нужно в списке инициализации конструктора.
Методы, не изменяющие состояния объекта (селекторы), рекомендуется описывать как константные. Спецификатор
const указывается в заголовке метода после списка параметров. Только константные методы можно применять к константным объектам. Напротив, к неконстантным объектам можно применять как обычные методы, так и константные. Можно определить одновременно константный и обычный методы с одинаковым списком параметров, тогда для константных объектов будет вызываться константный метод, для неконстантных – обычный.
class Vector {
const int size;
double *const data;
public:
Vector(int size):size(size),data(new double[size]) {}
~Vector() { delete []data; }
Vector(const Vector &);
int length() const { return size; }
double get(int i) const;
double &get(int i);
};
Vector::Vector(const Vector &v):
size(v.size),data(new double[size])
{
for(int i=0; i<size; ++i)
data[i]=v.data[i];
}
class BadIndex {};
double Vector::get(int i) const
{ if(i<0 || i>=size) throw BadIndex();
return data[i];
}
double & Vector::get(int i)
{ if(i<0 || i>=size) throw BadIndex();
return data[i];
}
Если некоторые поля нужно изменять в константных методах, то их нужно описать со спецификатором
mutable (использовать эту возможность с аккуратностью).
Кроме спецификатора
const у методов после списка параметров можно указать
& (применим к обычным объектам, lvalue) или
&& (только к временным объектам, rvalue). По умолчанию метод применим к обоим видам объектов.
Поля, описанные с помощью спецификатора static, являются общими для всех объектов класса. Фактически это глобальные переменные, видимостью которых можно управлять с помощью спецификаторов доступа. В файле реализации необходимо разместить поле в статической памяти и указать её начальное значение. Память, занимаемая статическим полем, не учитывается при определении размера объект с помощью операции
sizeof.
Статические методы могут обращаться только к статическим полям и вызывать другие статические методы. Этим методам не передается указатель
this. Вызывать эти методы можно либо обычным образом, либо через имя класса и
::
//
class One { //
int a;
static One *o; //
One(int x):a(x) {} //
One(const One&)=delete; //
One& operator=(const One&)=delete; //
public:
static One *instance(); //
~One() { o=nullptr; } //
int get() { return a; } //
};
//
One * One::o=nullptr;
One * One::instance()
{ if(o==nullptr) //
o=new One(10); //
return o;
}
//
int main()
{
cout<<One::instance()->get()<<"\n";
...
delete One::instance();
}
При использовании одновременно спецификаторов
constexpr и
static получается аналог глобальной
константы, видимостью которой можно управлять. Значение такой константы нужно непосредственно указывать при объявлении.
class Stack {
static constexpr int size=100;
int s[size];
int t=-1;
public:
void clear() { t=-1; }
bool isEmpty() const { return t==-1; }
bool isFull() const { return t==size-1; }
void pop();
int top() const;
void push(int);
};
Для целочисленных типов вместо
constexpr можно писать
const и также разрешается указывать значение при объявлении, но в общем случае
static const – это не изменяемое общее поле, значение которого задается позже в каком-то файле.