Категории
Самые читаемые книги
ЧитаемОнлайн » Компьютеры и Интернет » Программирование » Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Читать онлайн Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 313 314 315 316 317 318 319 320 321 ... 337
Перейти на страницу:
q)

{

  int x = p.distance_to(q); // вызов функции-члена 

  int y = difference(p,q);  // вызов с помощью математического

                            // синтаксиса

  // ...

}

Отметим, что функцию, объявленную с помощью ключевого слова friend, нельзя объявлять виртуальной.

A.12.2. Определения членов класса

Члены класса, являющиеся целочисленными константами, функциями или типами, могут быть определены как в классе, так и вне его.

struct S {

  static const int c = 1;

  static const int c2;

  void f() { }

  void f2();

  struct SS { int a; };

  struct SS2;

};

Члены, которые не были определены в классе, должны быть определены “где-то”.

const int S::c2 = 7;

void S::f2() { }

struct S::SS2 { int m; };

Статические константные целочисленные члены класса (static const int) представляют собой особый случай. Они просто определяют символические целочисленные константы и не находятся в памяти, занимаемой объектом. Нестатические данные-члены не требуют отдельного определения, не могут быть определены отдельно и инициализироваться в классе.

struct X {

  int x;

  int y = 7; // ошибка: нестатические данные-члены

             // не могут инициализироваться внутри класса

  static int z = 7; // ошибка: данные-члены, не являющиеся

                    // константами, не могут инициализироваться

                    // внутри класса

  static const string ae = "7"; // ошибка: нецелочисленный тип

                                // нельзя инициализировать

                                // внутри класса

  static const int oe = 7; // OK: статический константный

                           // целочисленный тип

};

int X::x = 7; // ошибка: нестатические члены класса нельзя

              // определять вне класса 

Если вам необходимо инициализировать не статические и не константные данные-члены, используйте конструкторы.

Функции-члены не занимают память, выделенную для объекта.

struct S {

 int m;

 void f();

};

Здесь sizeof(S)==sizeof(int). На самом деле стандартом это условие не регламентировано, но во всех известных реализациях языка оно выполняется. Следует подчеркнуть, что класс с виртуальной функцией имеет один скрытый член, обеспечивающий виртуальные вызовы (см. раздел 14.3.1).

A.12.3. Создание, уничтожение и копирование

Определить смысл инициализации объекта класса можно, определив один или несколько конструкторов (constructors). Конструктор — это функция-член, не имеющая возвращаемого значения, имя которой совпадает с именем класса.

class Date {

public:

  Date(int yy,int mm,int dd):y(yy),m(mm),d(dd) { }

  // ...

private:

  int y,m,d;

};

Date d1(2006,11,15); // OK: инициализация с помощью конструктора

Date d2;             // ошибка: нет инициализации

Date d3(11,15);      // ошибка: неправильная инициализация

                     // (требуются три инициализатора)

Обратите внимание на то, что данные-члены могут быть инициализированы с помощью списка инициализации в конструкторе. Члены класса инициализируются в порядке их определения в классе.

Конструкторы обычно используются для установления инвариантов класса и получения ресурсов (см. разделы 9.4.2 и 9.4.3).

Объекты класса создаются снизу вверх, начиная с объектов базового класса (см. раздел 14.3.1) в порядке их объявления. Затем в порядке объявления создаются члены класса, после чего следует код самого конструктора. Если программист не сделает чего-нибудь очень странного, это гарантирует, что каждый объект класса будет создан до своего использования.

Если конструктор с одним аргументом не объявлен с помощью ключевого слова explicit, то он определяет неявное преобразование типа своего аргумента в свой класс.

class Date {

public:

  Date(string);

  explicit Date(long); // используется целочисленное

                       // представление даты

  // ...

};

void f(Date);

Date d1 = "June 5, 1848"; // OK

f("June 5, 1848");        // OK

Date d2 = 2007*12*31+6*31+5; // ошибка: Date(long) — явный

                             // конструктор

f(2007*12*31+6*31+5);        // ошибка: Date(long) — явный конструктор

Date d3(2007*12*31+6*31+5);        // OK

Date d4 = Date(2007*12*31+6*31+5); // OK

f(Date(2007*12*31+6*31+5));        // OK

Если базовые классы или члены производного класса не требуют явных аргументов и в классе нет других конструкторов, то автоматически генерируется конструктор по умолчанию (default constructor). Этот конструктор инициализирует каждый объект базового класса и каждый член, имеющий конструктор по умолчанию (оставляя члены, не имеющие конструкторы по умолчанию, неинициализированными). Рассмотрим пример.

struct S {

  string name, address;

  int x;

};

Этот класс S имеет неявный конструктор S(), инициализирующий члены name и address, но не x. 

A.12.3.1. Деструкторы

Смысл операции удаления объекта (т.е. что произойдет, когда объект выйдет за пределы области видимости) можно определить с помощью деструктора (destructor). Имя деструктора состоит из символа ~ (оператор дополнения), за которым следует имя класса.

class Vector { // вектор чисел типа double

public:

  explicit Vector(int s):sz(s),p(new double[s]) { }

  // конструктор

  ~Vector() { delete[] p; }

  // деструктор

  // ...

private:

  int sz;

  double* p;

};

void f(int ss)

{

  Vector v(s);

  // ...

} // при выходе из функции f() объект v будет уничтожен;

  // для этого будет вызван деструктор класса Vector

Деструкторы, вызывающие деструкторы членов класса, могут генерироваться компилятором. Если класс используется как базовый, он обычно должен иметь виртуальный деструктор (см. раздел 17.5.2).

Деструкторы, как правило, используются для “очистки” и освобождения ресурсов. Объекты класса уничтожаются сверху вниз, начиная с кода самого деструктора, за которым следуют члены в порядке их объявления, а затем — объекты базового класса в порядке их объявления, т.е. в порядке, обратном их созданию (см. раздел A.12.3.1).

A.12.3.2. Копирование

Можно определить суть копирования объекта класса.

class Vector { // вектор чисел типа double

public:

  explicit Vector(int s):sz(s), p(new double[s]) { }

  // конструктор

  ~Vector() { delete[] p; }         // деструктор

  Vector(const Vector&);            // копирующий конструктор

  Vector& operator=(const Vector&); // копирующее присваивание

  // ...

private:

  int sz;

  double* p;

};

void f(int ss)

{

  Vector v(s);

  Vector v2 = v; // используем копирующий конструктор

1 ... 313 314 315 316 317 318 319 320 321 ... 337
Перейти на страницу:
На этой странице вы можете бесплатно скачать Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп торрент бесплатно.
Комментарии
КОММЕНТАРИИ 👉
Комментарии
Татьяна
Татьяна 21.11.2024 - 19:18
Одним словом, Марк Твен!
Без носенко Сергей Михайлович
Без носенко Сергей Михайлович 25.10.2024 - 16:41
Я помню брата моего деда- Без носенко Григория Корнеевича, дядьку Фёдора т тётю Фаню. И много слышал от деда про Загранное, Танцы, Савгу...