Стефан Дэвис - С++ для чайников .
- Название:С++ для чайников .
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс. Компьютерное издательство Диалектика
- Год:2007
- Город:Москва
- ISBN:0-7645-6852-3, 978-5-8459-0723-3
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стефан Дэвис - С++ для чайников . краткое содержание
1
empty-line
4
С++ для чайников . - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
_________________
210 стр. Часть 3. Введение в классы
Однако большинство программ в реальном мире состоят из нескольких файлов, которые компилируются каждый в отдельности, а уже затем связываются в единое целое. Поскольку компилятор не управляет порядком связывания, он не может влиять на порядок вызова конструкторов глобальных объектов в разных файлах.
В принципе в большинстве случаев порядок создания глобальных объектов не так уж и важен. Тем не менее иногда это может привести к ошибкам, которые потом очень сложно отследить ( такое случается довольно часто, чтобы обратить на это внимание в книге ). Разберём приведённый ниже пример.
class Student
{
public :
Student ( unsigned id ) : studentId( id ) { }
const int StudentId ;
} ;
class Tutor
{
public :
Tutor ( Student & s ) : tutoredId( s.studentId ) { }
int tutoredId ;
} ;
/* Создаём студента */
Student randy( 1234 ) ;
/* Назначаем студенту учителя */
Tutor jenny( randy ) ;
В этом примере конструктор Student присваивает студенту идентификатор, а конструктор класса Tutor записывает этот идентификатор студента, которому нужен учитель. Программа объявляет студента randy , а затем назначает ему учителя jenny .
При этом подразумевается, что randy создаётся раньше, чем jenny ; в этом-то и состоит проблема. Представьте себе, что порядок создания этих объектов будет другим. Тогда объект jenny будет построен с использованием блока памяти, который пока что не является объектом типа Student , а значит, вместо идентификатора студента в randy будет находиться непредсказуемое значение.
«Приведённый выше пример несложен и несколько надуман. Однако проблемы, создаваемые глобальными объектами, могут оказаться гораздо коварнее. Во избежание этого не допускайте, чтобы конструктор глобального объекта обращался к другому глобальному объекту.»
[ Советы ]
Члены создаются в порядке их объявления...211
Члены класса создаются в соответствии с порядком, в котором они объявлены внутри класса. Это не так просто и очевидно, как может показаться на первый взгляд. Рассмотрим пример.
class Student
{
public :
Student ( int id , int age ) : sAge( age ) , sId( id ) { }
const int sId ;
const int sAge ;
} ;
_________________
211 стр. Глава 17. Аргументация конструирования
В этом примере sId создаётся до sAge , несмотря на то что он стоит вторым в инициализирующем списке конструктора. Впрочем, единственный случай, когда можно заметить какую-то разницу в порядке конструирования, — это когда оба члена класса имеют конструкторы, которым присуще какое-либо общее побочное действие.
Деструкторы удаляют объекты в порядке, обратном порядку их создания...212
В каком бы порядке ни вызывались конструкторы объектов, вы можете быть уверены, что их деструкторы будут вызваны в обратном порядке. ( Приятно сознавать, что хоть одно правило в С++ не имеет никаких "если", "и" или "но". )
_________________
212 стр. Часть 3. Введение в классы
ОГЛАВЛЕНИЕ
В этой главе...
►Копирование объекта 213
►Автоматический конструктор копирования 215
►"Мелкие" и "глубокие" копии 217
►Временные объекты 221
Конструктор — это специальная функция, которая автоматически вызывается С++ при создании объекта с тем, чтобы предоставить ему возможность проинициализировать самого себя. В главе 16, "Создание и удаление объектов", описаны основные концепции применения конструкторов, в главе 17, "Аргументация конструирования", вы познакомились с разными типами конструкторов. А в настоящей главе рассматривается частный случай, известный под названием копирующего конструктора ( или конструктора копирования ).
►Копирование объекта...213
Конструктор, который используется С++ для создания копий объекта, называется копирующим конструктором, или конструктором копирования. Он имеет вид X::Х( Х & ) ( или X::X( const Х & ) ), где X — имя класса. Да, это не ошибка — это действительно конструктор класса X, который требует в качестве аргумента ссылку на объект класса X . Это звучит несколько бессмысленно, но не торопитесь с выводами и позвольте объяснить, зачем такое "чудо" в С++.
Зачем нужен копирующий конструктор...213
Подумайте о том, что будет происходить в программе, если вы вызовете следующую функцию:
void fn( Student fs )
{
/* Некоторые действия */
}
int main( int argcs , char* pArgs[ ] )
{
Student ms ;
fn( ms ) ;
return 0 ;
}
При вызове описанной функции fn( ) ей будет передан в качестве аргумента не сам объект, а его копия.
_________________
213 стр. Глава 18. Копирующий конструктор
«В С++ аргументы функции передаются по значению.»
[ Помни! ]
Теперь попробуем понять, что же значит — создать копию объекта. Для этого требуется конструктор, который будет создавать объект ( даже если копируется уже существующий объект ). С++ мог бы побайтово скопировать существующий объект в новый, но как быть, если побайтовая копия не совсем то, что нам нужно? Что, если мы хотим нечто иное? ( Не спрашивайте у меня пока, что такое это "иное" и зачем оно нужно. Немного терпения! ) У нас должна быть возможность самим определять, как будет создаваться копия объекта.
Таким образом, в приведённом выше примере необходим копирующий конструктор, который будет выполнять копирование объекта ms при вызове функции fn( ) . Этот частный копирующий конструктор и есть Student::Student( students ) ( попробуйте-ка произнести эту скороговорку... ).
Использование конструктора копирования ...214
Лучший путь понять, как работает конструктор копирования, — это увидеть его в действии. Рассмотрим приведённый ниже пример с классом Student .
//
/* CopyConstructor — работа конструктора копирования */
//
#include
#include
#include
#include
using namespace std ;
const int MAXNAMESIZE = 40 ;
class Student
{
public :
/* conventional constructor — обычный конструктор */
Student( char *pName = "no name" , int ssId = 0 )
{
strcpy( name , pName ) ;
id = ssId ;
cout << "Конструируем " << name << endl ;
}
/* Копирующий конструктор */
Читать дальшеИнтервал:
Закладка: