class Example
{
public:
explicit Example(double x);
// Конструктор инициализации - с параметрами
};
При таком объявлении неявное конструирование, т.е. создание
экземпляров этого класса без явного вызова 'Example(...)' станет невозможно.
Example x(0.0);
// ОК, явный вызов конструктора
Example x = 0.0;
// ошибка, неявный вызов конструктора
void func(Example x);
// объявление функции с параметром типа 'Example'
func(0.0);
// ошибка - вызов функции с неявным конструированием параметра
func( Example(0.0) );
// ОК - вызов функции с явным конструированием
//
параметра
Конструктор класса осуществляет инициализацию всех необходимых
ресурсов, включая поля класса. При вызове конструктора класса
последовательно в порядке объявления вызываются конструкторы всех полей
класса. Последовательность вызова конструкторов не зависит от выбора того
или иного способа инициализации, описанных немного дальше.
// Класс, задающий точку на плоскости из примера про структуры
class Point
{
// закрытые по умолчанию поля
double x;
double y;
public:
Point(string str)
{
cout << "Point::Point(" << str << ")" << endl;
}
};
// Класс, задающий линию между двумя точками на плоскости
71
class Line
{
Point start{"start"};
Point end{"end"};
public:
Line()
{
cout << "Line::Line" << endl;
}
}line;
При создании объекта 'line' класса 'Line' код из примера выше вначале
вызовет конструктор для поля 'start', затем 'end' и уже затем конструктор
Line::Line(). На консоли будет напечатано:
Point::Point(start)
Point::Point(end)
Line::Line
Допустимы несколько способов инициализации полей класса. Наиболее
простой способ - инициализация в классе. Она осуществляется как обычная
инициализация объектов за исключением инициализации в функциональном
стиле с круглыми скобками: 'int x(1);'
class Point{
int _x{1};
// один способ написать инициализацию в классе
int _y = 2;
// другой способ написать инициализацию в классе
public:
// конструктор инициализации
Point(int x, int y)
{
...
// дальнейшая инициализация по необходимости. _x и _y уже были
//
проинициализированы в порядке объявления
}
};
Следующий способ - инициализация в списке инициализации
конструктора, который начинается после заголовка конструктора, отделяется
двоеточием, а элементы списка разделяются запятой. Порядок следования
элементов в списке инициализации не имеет значения, инициализация все
равно осуществляется в порядке объявления. Можно совмещать с предыдущим
способом инициализации в классе, но способ инициализации в списке
конструктора будет иметь преимущество, и вызван будет только он. При
инициализации в списке оператор присваивания (знак '=') не применяется.
class Point{
int _x,_y;
public:
Point(int x, int y): _x{x},_y{y}
{
72
...
// дальнейшая инициализация
}
};
class Point{
int _x,_y;
public:
Point(int x, int y)
{
// здесь это не очень удачный способ. Вначале будут вызваны
//
конструкторы (в данном примере - по умолчанию), и потом значения
//
полей будут переопределены операторами ниже
_x = x;
_y = y;
}
};
При вызове деструктора класса деструкторы его полей вызываются в
обратном порядке по сравнению с порядком конструирования.
Для подведения итога небольшое резюме всего сказанного о классах до
этого:
class Example {
// Новый тип - класс Example
private:
// закрытая секция доступна только для членов класса
protected:
// защищенная секция доступна для членов класса и
//
членов производных классов
public:
// члены открытой секции доступны всем
int x;
// поле класса
void f();
// метод класса
void g() {return;}
// метод, определенный в классе, разворачиватся как
// inline
функция
void h() const;
// метод, не изменяющий поля класса
int operator+(int y); // t+y
вызывает t.operator+(y)
int operator-(); // -t
вызывает унарный оператор t.operator-()
Example(): x(1) {}
// Конструктор со списком инициализации
Example(const Example& e): x(e.x) {} //
Конструктор копирования
Example& operator=(const Example& t) {x=t.x; return *this; }
// Оператор
//
присваивания
~Example(); //
Деструктор
explicit Example(int a);
// Разрешить инициализацию t=Example(3),
//
запретив t=3
operator int() const {return x;}
// Оператор преобразования.
//
Разрешить преобразование int(t)
friend void i();
// Глобальная функция i() имеет доступ к "private"
friend class U;
// Члены класса U имеют доступ к "private"
static int y;
// Общее поле для всех объектов типа Example
static void l();
// Общий код для всех объектов типа Т.
73
// имеет доступ только к статическим данным
class Z {};
// Вложенный class Example::Z
typedef int V;
// Вложенное определение типа.
// Example::V
означает int
};
void Example::f() {
// Определение функции члена f класса Example
this->x = x;} // this
адрес собственного экземпляра (means x=x;)
int Example::y = 2;
// Инициализация статического члена обязательна
Example::l();
// Вызов статического метода
struct Example {
// В struct всё открыто по умолчанию:
// class Example { public:
Do'stlaringiz bilan baham: |