Г. Шилдт - Полный справочник по C++ (1109478), страница 90
Текст из файла (страница 90)
Обратите особое внимание на объявление объекта оЬ в функции взазп() . Оператор $ тус1авв оЬ = 4з автоматически преобразуется в вызов конструктора в(ге1авв() с параметром 4. Иначе говоря, компилятор не отличает его от оператора $ тус1авв оЬ(4]з Чтобы избежать неявного преобразования аргумента, можно использовать ключевое слово ев р11езс.
Спецификатор евр1зсХе применяется только к конструкторам. Конструктор с атрибутом ехр11езе используется только при обычном вызове. Он не выполняет никаких автоматических преобразований. Например, если конструктор зяуе1авв(] обладает атрибутом езЕР11с1С, автоматичЕСКОЕ ПрЕОбразование его аргумента не производится. Рассмотрим вариант, в котором объявлен явный конструктор класса туе1авв. 41пс1це]е <говегеаш> цвьпд пашеврасе вЫз с1авв щус1авв ( ьпс аз р Ь) (сз ехр11сгс шус1авв((пс х) ( а = хз ьпг дега(] ( геецгп аз ]з Теперь возможен только один способ вызова конструктора.
) щус1авв оЬ(4) з Инициализация $ щус1авв оЬ = 4з /! Ошибка теперь невозможна. П Инциализация членов класса В предыдуших главах мы рассматривали инициализацию членов класса внутри конструкторов. Например, следувнцая программа содержит класс мус1авв с двумя целочисленными членами пувзь и пцазв, которые инициализируются внутри конструктора. Фьпс1цде <ьовсгеаш> цвьпд пащеврасе все(з с1авв Мус1авв ( 1 па гп.апл з 1пс пшавз рцЬ11сз у* Члены пыпл и пцазв инициализируются внутри конструктора с помощью обычной синтаксической конструкции.
*/ Мус1авв(1пг х, з.пг у) Часть ]]. Вацек С++ пшпл = кз пшгВ = уз апс деспшпАО ( гегцсп пизплз зпе дегншпВ() ( сепцсп пшпвз )з зпс паап() ( Иус1аэе оЬ1(7, 9), оЬ2(5, 2) З соне « "Значения в объекте оЫ равны " « оЬ1.деепшпВ() « " и " « оЫ .десышпл() «епб1з соис « "значения в объекте оЬ2 равны " « оЬ2.десишпВ() « " и " « оЬ2.десниыл() ссепб1з тесшсп Оз В этом примере переменные-члены витя и пшпв инициализируются внутри конструктора класса иус1авв как обычно.
Однако такой подход оказывается приемлемым не во всех случаях. Например, если бы переменные поил и пити были константными, объявление класса выглялело бы так. с1ава Иус1авв ( сопев апе пшплз У/ Константный член сопэс Ьпе пшпвз з'/ Константный член В этом случае данным переменным ничего нельзя присвоить. Аналогичные проблемы возникают, если членом класса является ссылка, которую необходимо инициализировать, и если в классе не предусмотрен конструктор по умолчанию. Чтобы решить эту проблему, в языке С++ был предложен альтернативный способ инициализации членов класса при создании объекта. Синтаксическая конструкция, предназначенная для инициализации членов класса, похожа на конструктор базового класса.
Она имеет следующий вид. конструктор ( список аргументов): тепзЬег2 ( оничиализа тор ), тетЬет2 (иниииапизатор ), /Е тетЬег)з(инициаззизотор) ( // Тело конструктора ) Члены класса, подлежащие инициализации, перечисляются перед телом конструктора и отделяются двоеточием от имени конструктора и списка аргументов. Иницнализашзю членов класса и вызовы конструкторов базового класса можно смешивать в одном выражении. Перепишем класс иуб1авв, сделав члены пыив и пцазв константными Инициализация этих членов выполняется с помощью списка инициализации.
аапс1иде саовесеазп» иеапд папзеврасе абаз с1аэа Иус1авв ( аспас апс пшплз /з' константный член Глава аа. Пространства имен„преобразования функций и другие новвества сопят Рпс пшеВз // Константный член рцЫз.с з /* Члены пцазд и пцпВ инициалиэируптоя внутри конСтрУктора с помощью списка инициализации. */ МуС1аав (1псх, Рпе у) з пошл(х), пишВ(у) () зпс деенцплО ( гесигп пошлз зпт десиошВ() ( геспгп пцшлз з.пс шали() МуС1аее оЬ1(7, 9), оЬ2(5, 2)з соме « "Значения в объекте оЬ1 равны " « оЬ1.десношв() « " и " «« оЬ1.десншаАО «епд1з соцс « "значения в объекте оЬ2 равны " « оь2.десицщВО « " и " « оЬ2.дееншпдО «епб1з гееигп Оз Обратите внимание на то, что члены пцаза и ппжв инициализируются оператором $ МуС1авв(1псх, 1пе у)зишаша(х), пипВ(у) () Здесь переменная пошл инициализируется значением аргумента х, а пзлав — значением переменной у. Хотя члены ползя и пошл имеют атрибут сопев, цри создании объекта класса мус1авв им присваиваются начальные значения х и у, поскольку для этого используется список инициализации.
Такой способ инициализации особенно полезен, если член класса имеет тип, для которого не предусмотрен конструктор по умолчанию, рассмотрим еше одну версию класса взус1авв, в котором два целочисленных значения хранятся в объекте класса тпева1т. // Зта программа содержит ошибку и не компилируется. Еьпс1цбе <Ровегеаш> цв(пд пашеврасе аебз с1аве 1псра(г ( рцЬ11сз 1пс аз з.пс Ьз тззтразг(зпе з., тпе З) з а(1), Ыб) () ) с1авв МуС1авв ( 1ПСРаут ПцШВЗ // бщнбКаз КЛаСС 1ПСРатт НЕ СОЛЕРжИт // конструктор по умолчанию.
рцЫзсз // Этот фрагмент не работает! МуС1авв(1псх, тпс у) ( ползя.а = хз поле.Ь = у; ) Часть П. Язьщ С++ з.пс десншпд() ( теситп пипзв.аз ] ъпс десншпВО ( пееитп пшпв.ьг Рпс пзазп() ( НуС1авв оЬ1(7, 9), оЬ2(5, 2)з соне « "Значения в объекте оЬ1 равны ' « оЫ.дееиипзв() « " и " « оЬ1.дееиипзл() «епй1з соне « "значения в объекте оЬ2 равны " « оь2.деснзлпВ() « " и " « оь2.деснипьзз() «епбъз теситп оз ) Эта програлзма не компилируется, так как класс хпева1т содержит лишь один конструктор и имеет два аргумента.
Однако объект пшпв в классе нус1авв объявлен без параметров, а значения переменных а и Ь задаются в конструкторе класса муС1авв. Это порождает ошибку, поскольку предполагается, что при созлании объекта класса Хпсваът должен быть доступен конструктор по умолчанию (т.е. конструктор без параметров), а это условие не выполнено. Чтобы решить эту проблему, в класс хпеваът следует добавить конструктор по умолчанию. Однако это возможно лишь тогда, когда доступ к исхолному коду класса полностью открыт, а это условие выполняется не всегда. й таких случаях следует применять список инициализации членов класса, как показано ниже.
// Исправленная версия программы. Мъпс1иде «ъовстеапзь ивъпд пазпеврасе вес)з с1авв тпСРа1т [ риЫз.с з 1пе аг тпс Ьз Хпераът(ъпт 1, ъпп б) з а(з) ° ЫЭ) () с1авв муС1авв ( Тпера1т пшпвз // Теперь можно~ риЫъс з // Применение списка инициализации. ИуС1авв(зпсх, зпе у) з пшпв(х,у) () ъпс деснипьчО ( теситп пшпв.аз ) 1пе деенитВО ( тееитп зштв.Ьз ъпс зпаз.п() ( НуС1авв оЬ1[7, 9), оЬ2 (5, 2) з соне « "Значения в объекте оЬ1 равны " «оЬ1.дееишпВ() « " и " «оЬ1.сепиям() <сепй1з Глава 23.
Пространства имен, преобразования фувпций и другие новшества соне « "Значения в объекте оЬ2 равны " « оЬ2.дееппиВО сс " и " « оЬ2.деснопА() «епс(1у кеснкп 0; ) Теперь при создании объекта класса иус1авв инициализируется объект пвтв. Таким образом, конструктор по умолчанию не нужен. И последнее: члены класса создакпся и инициализируются в порядке своего объявления в классе, а не в порядке их перечисления в списке инициализации.
П Применение ключевого слова аап Несмотря на всю мощь и выразительность языка С++, в некоторых ситуациях его недостаточно. (Например, в языке С++ нет оператора, который блокировал бы прерывания.) Для особых ситуаций в языке С++ прелусмотрели "лазейку", позволяющую вставлять в программу ассемблерный код, игнорируя компилятор. Этой "лазейкой" является оператор вввк Используя его, в программу можно включать фрагменты ассемблерного кода, которые при компиляции остаются без изменения, а затем становятся частью выполняемого модуля. Оператор ввш имеет следующий вид.
)( авт( "еой "); Параметр сог)е представляет собой инструкцию на языке ассемблера, которая вставляется в программу. Олнако некоторые компиляторы позволяют также использовать иные формы оператора вввк авт инструкция; авт инструкция перекод на новую строку; авт ( поеяедоеатекьность инструкций ) В этих выражениях могут использоваться любые допустимые инструкции на языке ассемблера. Поскольку реализация этого свойства зависит от компилятора, детали следует искать в документации. В момент написания этой книги в компиляторе М)сгозой Ч)зыа! С++ для включения ассемблерного кода использовалось ключевое слово вюа, а в других кол1п иляторах — вввк рассмотрим пример. Фвпс1ыбе <1овскеат> пвьпд пашеврасе вее)," 1пе та1п() ( авт 1пе 5; // Генерируется прерывание номер 5.
кеесеп 0; При запуске этой программы пол управлением системы ПОБ генерируется инструкция ХИТ 5, которая вызывает функцию печати экра)га (рпп(-зсгееп). Часть й. Язык С++ Г)римененое ключевага слова требует кцсашего знания языка ассемблера. Если вы не полностью овладели этим языкам, не рискуйте, поскольку вставка ашобачнсгс ассемблерного кода мткет закончиться плачевно. Л Спецификации связей В языке С++ можно указать, как функции связываются с программой. По умолчанию все функции связываются как функции на языке С++. Однако„используя спецификации связей ())пйане зрес)йсагюп), с программой можно связать функции, написанные на другом языке. Спецификация связей имеет следуюший вил.
и ехсегп "(апзиаве прататип функции Параметр !апзиале задает требуемый язык. Все компиляторы помогают связывать функции на языке С++ и С. Кроме того, некоторые компиляторы позволяют подключать функции, написанные на языках Гопгап, Рекса! или ВАЯС. (Детали изложены в документации, сопровождаюшей компилятор.) Следуюшая программа связывается функцией згусвипо(), написанной на языке С. Евпс1ис)е <Еоеггееп> ив(пд патезрасе згд; ехсегп "С" чозд туСЕипс(); Епг п|езп() ( туСЕипс О; гегигп сы // Функиия на языке С. чоЫ куСЕипс() ( соиг « "Функция на языке с.1п"г Ключевое слово енеез а являепгя неотьемлемой частью спецофиквцои связей. Кроме пюга„спецификация связей даггкне бокль глобальной: ее нельзя применять внуглри функции.