|
Программирование >> Инициализация объектов класса, структура
(a) Word::Word( char *ps, int count = 1 ) : ps ( new ch a r[st rlen (ps ) 4 ps( new char[strlen(ps)+1] count( count if ( ps ) strcpy( ps, ps ); else { ps = 0; count = 0; (b) class CL1 { public: CL1() { c.real(0.0); c.imag(0.0); s = not set ; } ... private: complex<double> c; string s; (c) class CL2 { public: CL2( map<string,location> *pmap, string key ) : text( key ), loc( (*pmap)[key] ) {} ... private: location loc; string text; Account oldAcct( Anna Livia Plurabelle ); 14.6. Почленная инициализация A Инициализация одного объекта класса другим объектом того же класса, как, например: class Account { public: ... private: char * name; unsigned int acct nmbr; double balance; определение нашего класса Account: inline Account:: Account( const Account srhs ) { name = rhs. name; acct nmbr = rhs. acct nmbr; balance = rhs. balance; то можно представить, что копирующий конструктор по умолчанию определен так: Почленная инициализация одного объекта класса другим встречается в следующих ситуациях: явная инициализация одного объекта другим: Account newAcct ( oldAcct ); extern bool cash on hand( Account acct ); if ( cash on hand( oldAcct )) передача объекта класса в качестве аргумента функции: ... передача объекта класса в качестве возвращаемого функцией значения: Account newAcct( oldAcct ); называется почленной инициализацией по умолчанию. По умолчанию - потому, что она производится автоматически, независимо от того, есть явный конструктор или нет. Почленной - потому, что единицей инициализации является отдельный нестатический член, а не побитовая копия всего объекта класса. Такую инициализацию проще всего представить, если считать, что компилятор создает специальный внутренний копирующий конструктор, где поочередно, в порядке объявления, инициализируются все нестатические члены. Если рассмотреть первое extern Account consolidate accts( const vector< Account >& ) Account final acct; выполнить финансовую операцию return final acct; вызывается пять копирующих конструкторов класса string определение непустого последовательного контейнера: vector< string > svec( 5 ); (В этом примере с помощью конструктора string по умолчанию создается один временный объект, который затем копируется в пять элементов вектора посредством копирующего конструктора string.) вставка объекта класса в контейнер: svec.push back( string( pooh )); Для большинства определений реальных классов почленная инициализация по умолчанию не соответствует семантике класса. Чаще всего это случается, когда его член представляет собой указатель, который адресует освобождаемую деструктором память в хипе, как, например, в нашем Account. В результате такой инициализации newAcct. name и oldAcct. name указывают на одну и ту же C-строку. Если oldAcct в1ходит из области видимости и к нему применяется деструктор, то newAcct. name указывает на освобожденную область памяти. С другой стороны, если newAcct модифицирует строку, адресуемую name, то она изменяется и для oldAcct. Подобные ошибки очень трудно найти. Одно из решений псевдонимов указателей заключается в том, чтобы выделить область памяти для копии строки и инициализировать newAcct. name адресом этой области. Следовательно, почленную инициализацию по умолчанию для класса Account нужно подавить за счет предоставления явного копирующего конструктора, который реализует правильную семантику инициализации. Внутренняя семантика класса также может не соответствовать почленной инициализации но умолчанию. Ранее м1 уже объясняли, что два разных объекта Account не должны иметь одинаковые номера счетов. Чтобы гарантировать такое поведение, мы должны подавить почленную инициализацию по умолчанию для класса Account. Вот как выглядит копирующий конструктор, решающий обе эти проблемы:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |