Язык программирования Си++ (1119468), страница 2
Текст из файла (страница 2)
Одновременноесуществование нескольких конструкторов имеет специальноенаименование – перегрузка конструкторов• Все конструкторы должны отличаться друг от друга количествоми/или типами параметров• Конструктор без параметров называется конструкторомумолчания. Если в классе не описан никакой другой конструктор(и только в этом случае), конструктор умолчания генерируетсяавтоматически• Конструкторы не возвращают никаких значений24Конструкторы копированиязначений объектов• Прототип конструкторов копирования выглядит так:Box (Box &a);// илиBox (const Box &a);• Наличие спецификатора const означает, что самкопируемый объект при копировании не изменяется• Если конструктор копирования не определён в классеявно, он будет сгенерирован автоматически, при этомпроизводится поверхностное (почленное) копированиеданных объекта:Box (const Box &a) { len = a.len; wid = a.wid; hei = a.hei; }25Запускконструктора копирования• При определении новых объектов, инициируемыхзначениями ранее созданных объектов:Boxb4 = Box (4, 7, 1);• При создании временного объекта для инициализацииуказателя на него (без копирования объекта!), но споследующей инициализацией описываемого объектазначением, извлекаемым по указателю:Box * b5 = new Box (2, 3, 5);Box b6 = * b5;26Свойстваконструкторов копирования• Конструкторы копирования используются при передачепараметров и при возврате результата функции по значению• При передаче параметров по ссылке копирования нет!• Наличие явно описанного конструктора копирования блокируетвозможность автоматической генерации конструктораумолчания• Наличие явно описанного конструктора умолчания никак невлияет на автоматическую генерацию конструктора копирования• В некоторых компиляторах при обработке инициализации видаBox b4 = Box (4, 7, 1) вместо конструктора копированияиспользуется конструктор Box b4 (4, 7, 1) с тремя параметрами27без создания временного объекта и его копированияУказатель this• Указатель this – это указатель на объект, отимени которого производится вызов метода• Указатель this – это всегда указатель на самыйпервый (неявно заданный) операнд метода,который является объектом данного класса• Пример использования указателя thisBox (Box & a) { if (this != & a){ len = a.len; wid = a.wid; hei = a.hei; }это конструктор копирования} //28Использование указателя thisclass string { char p [SIZE];public: voidconcatintlengthvoidtolowvoidtrim};string s1, s2;s1.concat (s2);//s1.trim ();//s1.tolow ();//string s3 = s1;//// ...(string &); // конкатенация строк();// длина строки();// в нижний регистр();// убрать пробелыприсоединение s2 к s1удаление пробелов спереди и сзадиперевод в нижний регистркопирование s1 в s3• Здесь каждая последующая операция применяется к объекту s1, значениекоторого изменяется в результате предыдущей операции.
Объект s1 всегдаявляется объектом класса string29Использование указателя thisclass string { char p [SIZE];// ...public: string & concat (string &); // конкатенация строкintlength ();// длина строкиstring & tolow ();// в нижний регистрstring & trim ();// убрать пробелы};string & string::concat (string & s1) { strcpy (p + length (), s1.p);return * this; // разыменование this, возврат ссылки на сам объект}// ... теперь можно писать так:string s1, s2;string s3 = s1.concat (s2).trim ().tolow ();• Результатом работы метода string::concat() является ссылка на его жеобъект s1, это позволяет сразу вызвать метод string::trim(), которыйаналогичным образом возвращает ссылку на s130Вызовконструкторов класса• При создании объекта (при обработке описания объекта, при созданиивременных объектов в выражениях, при создании локальных объектов длязначений параметров функций):Box b (3, 4, 5);• При создании объекта в динамической памяти (new), при этом, сначалаотводится необходимая память, а затем работает нужный конструктор:Box * pb;pb = new Box (3, 4, 5);• При включении объектов в состав других объектов наряду с собственнымконструктором вызывается конструктор объекта – члена класса• При создании объекта производного класса дополнительно вызываетсяконструктор базового класса.• Для статических объектов конструктор вызывается при запуске программы• При возбуждении исключительной ситуации для создания временного31объекта, передаваемого перехватчикамПри вызовеконструктора класса1.
Вызываются конструкторы базовых классов (если естьнаследование class Z: public Y {...})2. Автоматически вызываются конструкторы умолчаниявсех вложенных объектов в порядке их описания вклассе3. Вызывается собственный конструктор, при его вызовевсе поля класса уже существуют, они получили своизначения при их инициализации, под них выделенапамять, следовательно, их можно использовать втеле конструктора32Вызовконструкторов копирования• В случае:••••Box a (3, 4, 5);Box b = a; // a – параметр конструктора копированияВ случае:Box c = Box (3, 4, 5);Сначала создаётся временный объект и вызывается обычныйконструктор (не копирования), а затем работает конструкторкопирования при создании объекта ‘c’. В некоторых компиляторахвременный объект может не создаваться, в этом случае вызываетсяобычный конструктор с нужными параметрами:Box c (3, 4, 5);При передаче параметров функции по значению (созданиелокального объекта)При возврате результата работы функции в виде объектаПри возбуждении исключительной ситуации и передаче объекта33исключения перехватчикуДеструкторы объектов• Деструктор не имеет параметров и не возвращает никакогозначения: ~<имя_класса>();• Если деструктор не описан, он генерируется автоматически• Деструктор по умолчанию ничего не делает (его тело –пусто) и нужен только для парности соответствующемуконструктору• Деструктор вызывается:1.
При выходе из зоны описания объекта2. При выполнении операции delete для указателя,получившего значение при выполнении операции new(при этом сначала работает деструктор, а затемосвобождается память, занятая объектом)34Деструкторы объектов• При выходе из блока для всех автоматических объектоввызываются деструкторы, в порядке, противоположномпорядку выполнения конструкторов:1. Собственный деструктор, при этом в момент началаработы программы деструктора поля данных класса ещёне очищены и, следовательно, доступны дляиспользования, доступны в деструкторе также полябазовых классов (если есть наследование)2.
Деструкторы всех вложенных объектов в порядке,обратном порядку их описания в классе3. Деструкторы базовых классов (если есть наследование)35Работа с динамической памятью• Объекты размещаются в памяти аналогично данным языка Си:существуют статические объекты и автоматические объекты, выборопределяется местом определения объектов (не классов!)• Вне процедур могут определяться только статические (static) иглобальные объекты , внутри – ещё и автоматические объекты• Для создания объекта в свободной памяти используется операцияnew, для его уничтожения применяется операция delete• Размер пространства, захватываемого при выполнении операции new,точно соответствует размеру объекта-операндаintint * p = new int; // создание нового объекта p5* p = 5; // присваивание значения объекту p• Явное создание нового объекта в свободной памяти конструктором:Box * b4 = new Box (2, 3, 5);delete b4;• Операции new и delete можно переопределять36Работа с динамической памятью• Создавать можно и массивы объектов.
В этом случае операциясоздания обозначается как new[]pint * p;p = new int [3]; // создание массива из 3-х объектовintintint• Массив уничтожается операцией delete[]• Размер освобождаемой памяти контролируется системой и неуказывается в операции delete[]intpdelete p; // уничтожение скаляраdelete [] p; // уничтожение массиваpint• Применение скалярного варианта операции освобождения памяти куказателю, по которому размещается массив приведёт во времяработы программы к ошибке• Операции new[] и delete[] можно переопределять37Работа с динамической памятьюclass string { char * p; int size;public: string (const char * str); // конструктор// выполняет выделение памяти под строку// и инициализацию этой памяти~ string (); // освобождение памяти};string::string (const char * str) // для инициализации константами{ p = new char [(size = strlen (str)) + 1];strcpy (p, str);}string::~string () { delete [] p; }void f() { string s1 (“Знак”);string s2 = s1;string s3 (“Система”); /* ...
*/ s3 = s1; // …}38Работа с динамической памятьюvoid f() { string s1 (“Знак”);string s2 = s1;string s3 (“Система”);s3 = s1;}s14s2// копирование полей p и size/* ... */// присваивание полей p и sizeЗ н ак 0Си с т е ма 0s3477439Работа с динамической памятьюstring::string (const string & a){// копируются не указатели, а значения:p = new char [(size = a.size) + 1];strcpy (p, a.p); }string::~string () { delete [] p; }// деструктор не меняетсяvoid string::operator=(string & a){// присваиваются не указатели, а значения:delete [] p; // уничтожение старого значенияp = new char [(size = a.size) + 1]; strcpy (p, a.p);}s14З н ак 0s2Си с т е ма 0s34З н ак 0774З н ак 040Работа с динамической памятьюstring::string (const string & a){p = new char [(size = a.size) + 1];strcpy (p, a.p); }string::~string () { delete [] p; }string & string::operator=(string & a){if (this != & a) {delete [] p; // уничтожение старого значенияp = new char [(size = a.size) + 1]; strcpy (p, a.p);} return * this;}s3 = s2 = s1; // теперь такое присваивание допустимоs14З н ак 0s2Си с т е ма 0s34З н ак 0774З н ак 041Константные члены класса• Иногда необходима уверенность, что метод не будет менять значенияпереданных ему параметровstring & string::concat (const string & s) { … }• Ошибочными являются операторы, в которых меняется значение такихпараметров, ошибочными являются вызовы методов для такихпараметров (константных объектов), поскольку нет информации о том,какие операции они производят над своими объектами:int string::length (); // нет указания неизменности объектаstring & string::concat (const string & s){ /* … */ s.length () /* … */ } // Ошибка!• В языке Си++ можно указывать, что некоторые методы не меняютсостояния своих объектов (ключевое слово const после скобокгруппирования формальных параметров):int string::length () const;42Константные члены класса• Как только метод объявлен константным, ему явно разрешается бытьвызванным для константных объектов типа string.
Тем самым, станетдопустимой реализация метода string::concat () с константнымформальным параметром:int string::length () const;// длина строкиstring & string::concat (const string &s) // конкатенация строк{ string temp = * this;delete [] p;p = new char [(size = temp.length () + s.length ()) + 1];strcpy (p, temp.p);strcpy (p + temp.length (), s.p);return * this;}разрешено для константы “s”,если метод length() тоже константный!43Статические члены класса• В классах допускаются статические члены (поля данных и методы)• Статические методы классов не имеют неявного параметра,соответствующего указателю на активный объект, в телестатических методов класса нельзя использовать указатель this• Для статического члена класса память отводится один раз в моментзапуска программы, как для обычной статической переменной• Статическое поле представляется в единственном экземпляре длявсех экземпляров этого класса• Обращаться к статическому члену можно без указания имениобъекта, во избежание неоднозначности можно использовать имясамого класса: class A { public: static int x; static void f (char c); };/* … */A::x = 10; A::f (‘a’);• Для работы со статическими полями используют статическиеметодыСтатические члены класса• При работе со статическими полями классов не возникаетнеобходимости выделять память под экземпляры класса:class X { public: int a; static int count;X (int i) { a = i; count ++; }};• Инициализация статических полей выполняется вне описания класса:int X::count = - 1;int main () { X g(1), z (10); cout << X::count; }• Обращение к статическому члену класса может происходить спомощью какого-либо из объектов (g.count, z.count), либо с помощьюимени класса (X::count), которое можно использовать даже доопределения первого объекта: вызов через объект (g.count) возможентолько после оператора определения этого объекта (g)45Статические члены класса• Инициализацию вне класса можно использовать даже, еслистатическое поле определено в закрытой части класса:class X { static int count; public: int a;X (int i) { a = i; count ++; }void c_print () { cout << count << endl; }};int X::count = –1;• Обычные методы нельзя вызывать до создания первого объекта,чтобы вызвать функцию до создания первого объекта, её следуетобъявить статическим членом класса:static void c_print () { cout << count << endl; }• Статическим методом класса можно объявить только такой метод, вкотором используются только статические поля данных класса илидругие статические методы• Вызов статического метода:X::c_print ();46Статические члены класса• Статические методы класса не могут вызывать нестатические методы,нестатические методы могут вызывать статические• Константные методы класса не могут изменять значения полейданных класса, однако, они могут менять статические поля• Статический метод может создавать экземпляры классов (объекты), вчастности, экземпляры собственного класса:class X {X () {} ~X () {}public: static X& createX () { X * x1 = new X;cout << "X created”;return * x1; }static void destroyX (X & x1) { delete & x1;cout << "X destroyed”;}};int main () { X & xx1 = X::createX (); // .