printКлассы

printКонструктор

Определение: Конструктор – это специальный метод, имя которого совпадает с именем класса. Конструктор не имеет возвращаемого значения, даже void. Конструктор не может быть объявлен как const, static или virtual. Класс может иметь несколько конструкторов с разными сигнатурами.

Синтаксис: имя класса(тип параметра1, тип параметра2, …);

Задача: Инициализировать все поля.

Назначение: Вызывается компилятором автоматически при создании объектов:
  • для локальных объектов – при выполнении оператора, в котором они объявлены;
  • для глобальных статических объектов – перед вызовом функции main (порядок вызовов не определен), для собственных статических значений функции – при первом выполнении этой функции;
  • для объектов, создаваемых в динамической памяти – при выполнении операции new.

Замечания:
  • Перед выполнением тела конструктора, компилятором автоматически вызываются конструкторы для базовых классов, затем конструкторы для полей в порядке, указанном при объявлении класса.
  • Можно указать аргументы для вызова конструкторов базовых классов и полей, используя список инициализации, который записывается после : между заголовком и телом конструктора. В списке инициализации через запятую пишутся имена базовых классов или полей, в скобках указываются аргументы для конструкторов. Для базовых классов и полей, не указанных в списке инициализации вызываются конструкторы по умолчанию. Базовые классы и поля в списке инициализации рекомендуется перечислять в порядке, указанном при объявлении класса. Можно указать их в другом порядке, но ошибки использования неинициализированных полей станут менее заметными, так как вызовы конструкторов всё равно будут происходить в порядке, заданном при объявлении класса.
  • Конструктор не может быть вызван как метод, он вызывается только при создании объекта:
  • Выражение имя класса(аргументы) создает временный объект, уничтожаемый после выполнения оператора, в котором используется это выражение (скобки обязательны, даже если список аргументов пустой).
  • Выражение new имя класса(аргументы) создает объект в динамической памяти (если список аргументов пустой, скобки можно не писать).
  • Оператор объявления имя класса имя объекта(аргументы); создает новый объект в статической памяти или на стеке (если список аргументов пустой, скобки не пишутся).
Примеры:
class Stack {
  int size,t;
  int *s; 
public:
  Stack(int);
  bool isEmpty() { return t==-1; }
  bool isFull() { return t==size-1; }
  void pop();
  int top();
  void push(int);
};
Stack::Stack(int size)
{
  Stack::size=size;
  s=new int [size];
  t=-1;
}
void fun(const Stack &);
int main()
{
  Stack s1(100); // создается объект на стеке
  s1.push(10);
  ...
  fun(Stack(100)); // создается временный объект и передается по ссылке в функцию
  Stack *s2;
  s2=new Stack(100); // объект создается в динамической памяти
  s2->push(10);
  ...
}
Аналогичный синтаксис можно использовать для создания объектов стандартных типов:
int a(100); // вместо int a=100;
int *b;
b=new int(100); // выделить динамически память для int 
                // и инициализировать её числом 100 
Пример определения конструктора со списком инициализации
Stack::Stack(int size):
  size(size), // имя_поля(выражение) - нет коллизии имен
  s(new int [size]), t(-1)
{}
см. также пример для конструктора по умолчанию

Нестатическим полям можно указать значение по умолчанию, которое будет использовано, если в конструкторе это поле не будет инициализировано другим значением.
class Rational { 
  int p(0),q(1);
  Rational(){} // p=0, q=1
  Rational(int z):p(z){} // p=z, q=1
  Rational(int a, int b):p(a),q(b)
  { int c=gcd(a,b);
    p/=c; q/=c;
  }
};
Можно вызывать одни конструкторы класса из других в списках инициализации, чтобы не дублировать код.

Контейнерные классы теперь можно инициализировать, используя списки значений, как и обычные массивы. Для этого в C++ есть шаблонный класс std::initializer_list<T>. Объекты этого класса задаются в программе с помощью перечисления значений в {}, а класс должен иметь конструктор вида:
class IntList {
public:
  IntList(std::initializer_list<int> a);
};
IntList list{1,2,3,4,5}; // можно писать так IntList list={1,2,3,4,5};
Все стандартные контейнерные классы теперь имеют такой конструктор:
vector<int> v{1,2,3}; 
map<string,int> m{{"Tom",5},{"John",10}};
Списки значений можно также использовать в качестве аргумента для функций:
void f(std::initializer_list<int> a);
...
f({3,5,7});

При создании объектов аргументы конструктора можно указывать в фигурных скобках {}. Если у класса есть конструктор с параметром initializer_list, то при использовании {} будет вызван именно он, в остальных случаях разницы между этими вариантами нет. Также форму с {} можно использовать для инициализации полей структур без конструкторов. Форма с {} может использоваться неявно при возврате результата из функции.
struct Vector { int x,y; };
Vector a{1,2};
Vector turn(Vector b)
{ return {-b.y,b.x};
}
a=turn({2,3});
loading