Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Мизрохи С.В. -> "Turbo Pascal и объектно-ориентированное программирование" -> 27

Turbo Pascal и объектно-ориентированное программирование - Мизрохи С.В.

Мизрохи С.В. Turbo Pascal и объектно-ориентированное программирование — М.: Финансы и статистика , 1992. — 192 c.
ISBN 5-279-00903-2
Скачать (прямая ссылка): efektispolzc2000.djvu
Предыдущая << 1 .. 21 22 23 24 25 26 < 27 > 28 29 30 31 32 33 .. 105 >> Следующая

1. Инициализация членов класса (см. также правило 13).
2. Выполнение тела вызываемого конструктора.
(Для объектов базовых классов инициализация и выполнение кода внутри Конструктора происходит до инициализации производных классов.)
В отношении классов NamePtr это означает, что конструктор для идентификатора типа string всегда вызывается прежде, чем вы войдете в тело конструктора NamePtr. Встает единственный вопрос: какой конструктор string будет вызван?
public:
NamedPtr(const strings initName, T *initPtr);
private:
const strings name; T * const ptr;
};
Il Требует инициализации в списке инициализации. // Требует инициализации в списке инициализации.
Конструкторы и операторы
Это зависит от списка инициализации класса NamePtr. Если для name вы не укажете инициализирующий аргумент, для string будет вызван конструктор по умолчанию. Когда позднее для name будете выполняться присваивание внутри конструкторов NamePtr, будет вызван operator= . Это приведет к тому, что произойдут два вызова функций-членов string: один раз - конструктора по умолчанию, а другой раз - оператора присваивания.
С другой стороны, если вы используете список инициализации членов, чтобы указать, что name следует инициализировать значением in it Name, то name будет инициализировано только с использованием копирующего конструктора, посредством одного-единственного функционального вызова.
Даже в случае простого типа string стоимость лишнего вызова функции может быть значительной, и по мере того как классы становятся больше и сложнее, усложняются их конструкторы и увеличивается стоимость их вызова. Если вы возьмете за привычку везде, где это возможно, использовать список инициализации членов, не ограничиваясь только членами с const и ссылками, для которых это является обязательным, вы также уменьшите шансы неэффективной инициализации членов класса.
Другими словами, инициализация посредством списка инициализации всегда корректна и не менее, а часто более эффективна, чем присваивание внутри тела конструктора. Кроме того, она упрощает дальнейшую поддержку класса, поскольку, если тип члена класса позднее изменится так, что потребуется использование списка инициализации данных, вам ничего не придется менять.
Тем не менее может возникнуть ситуация, когда будет целесообразно использовать присваивание, а не инициализацию членов класса. Это случай, когда у вас имеется большое количество членов класса встроенных типов, и вы хотите, чтобы в каждом конструкторе все они инициализировались одинаковым образом. Вот пример класса, который можно отнести к данной категории: *¦
class ManyDataMbrs { t
public:
Il Конструктор по умолчанию. ManyDataMbrs() ; Il Конструктор копирования. ManyDataMbrs (const ManyDataMbrs& x) ; private:
int a, b, c,d, e, f,g, h; double і, j , k, 1, m,-
};
Предположим, что вы хотите инициализировать все переменные типа int значением 1, а все double - 0, даже если используется конструктор копирования. Используя список инициализации членов, вы должны были бы написать следующее:
ManyDataMbrs::ManyDataMbrs()
: а(1), Ь(1), с(1), d(l), е(1), f(l), g(l), h(l), i(0),
j (0) , k(0), 1(0), m(0) { • . . }
Правило 12
ManyDataMbrs::ManyDataMbrs(const ManyDataMbrs& x)
: a(l), b(l), c(l), d(l), e(l), f(l), g(l), h(l), i(0),
j (0) , k(0) , 1(0), m(0) , > • . . .і і
{ ... }
Это не просто неприятная и нудная работа. В краткосрочном плане такой код увеличивает вероятность ошибки, а в долгосрочном - затрудняет поддержку.
Вы, однако, можете воспользоваться тем фактом, что между инициализацией и присваиванием объектов встроенного типа (если они не константные и не ссылки) нет никакого функционального отличия, поэтому вполне допустимо заменить инициализационный список вызовом общей инициализирующей функции:
class ManyDataMbrs { ^public:
/ / Конструктор по умолчанию. ManyDataMbrs() ; // Конструктор копирования. ManyDataMbrs (const ManyDataMbrs& х) ; private: ' «
int a,b,c,d,e,f,g,h; * 1
double і, j , k, 1, nevoid init() ; Il Используется для инициализации членов-данных.
/oid ManyDataMbrs:: init ()
a = b = c = d = e = f = g = h=l; і = j = k = l = m= 0;
ManyDataMbrs::ManyDataMbrs()
init();
•К
anyDataMbrs::ManyDataMbrs(const ManyDataMbrs& x) init();
Поскольку инициализирующая функция - это внутреннее дело реализации Класса, не забудьте сделать эту функцию private.
Обратите внимание на то, что статические члены класса никогда не должны Инициализироваться в конструкторе. Они инициализируются только однажды
|в Ходе выполнения программы, поэтому нет смысла пытаться инициализировать Их каждый раз при создании объекта данного типа. В самом лучшем случае это °Удет неэффективным: зачем несколько раз платить за инициализацию объекта? |Кроме того, инициализация статических членов класса отличается от инициализации их нестатических эквивалентов, и этой теме посвящено правило 47.
62
ШИШ
Конструкторы и операторы
Правило 13. Перечисляйте члены в списке инициализации в порядке их объявления
Программисты на Pascal и Ada часто страдают от невозможности объявлять массивы с произвольными границами, то есть от 10 до 20 (вместо 0...10). Тот, кто давно имеет дело с С, считает, что любой уважающий себя программист всегда начинает отсчет с 0. Умиротворить приверженцев begin/end совсем не сложно. Все, что для этого необходимо, - определить свой шаблон класса массива:
Предыдущая << 1 .. 21 22 23 24 25 26 < 27 > 28 29 30 31 32 33 .. 105 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100