Конструктор
Определение:
Конструктор – это специальный метод, имя которого совпадает с именем класса. Конструктор не имеет возвращаемого значения, даже
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 *b;
b=new int(100); //
//
Пример определения конструктора со списком инициализации
Stack::Stack(int size):
size(size), //
s(new int [size]), t(-1)
{}
см. также пример для
конструктора по умолчанию
Нестатическим полям можно указать значение по умолчанию, которое будет использовано, если в конструкторе это поле не будет инициализировано другим значением.
class Rational {
int p(0),q(1);
Rational(){} //
Rational(int z):p(z){} //
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}; //
Все стандартные контейнерные классы теперь имеют такой конструктор:
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});