printКлассы

printСпециальные элементы класса

Поля, значения которых не меняются на протяжении всего времени существования объекта, рекомендуется описывать со спецификатором 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 – это не изменяемое общее поле, значение которого задается позже в каком-то файле.
loading