Чем интересно неявное преобразование конструктора



 

Автоматическое преобразование из типа аргумента конструктора в вызов конструктора само по себе имеет интересные последствия. Рассмотрим, например, следующий код.

 

 

Обратите внимание на то, что новое значение присваивается объекту о с помощью такой инструкции:

 

 

Использование данного формата возможно благодаря неявному преобразованию из типа int в тип myclass , которое создается конструктором myclass() . Конечно же, если бы конструктор myclass() был объявлен с помощью спецификатора explicit , то предыдущая инструкция не могла бы выполниться.

 

Синтаксис инициализации членов класса

 

В примерах программ из предыдущих глав члены данных получали начальные значения в конструкторах своих классов. Например, следующая программа содержит класс myclass , который включает два члена данных numA и numB . Эти члены инициализируются в конструкторе myclass() .

 

 

Результаты выполнения этой программы таковы.

 

 

Присвоение начальных значений членам данных numA и numB в конструкторе, как это делается в конструкторе myclass() , – обычная практика, которая применяется для многих классов. Но этот метод годится не для всех случаев. Например, если бы члены numA и numB были заданы как const ‑переменные, т.е. таким образом:

 

 

то им нельзя было бы присвоить значения с помощью конструктора класса myclass , поскольку const ‑переменные должны быть инициализированы однократно, после чего им уже нельзя придать другие значения. Подобные проблемы возникают при использовании ссылочных членов, которые должны быть инициализированы, и при использовании членов класса, которые не имеют конструкторов по умолчанию. Для решения проблем такого рода в C++ предусмотрена поддержка альтернативного синтаксиса инициализации членов класса, который позволяет присваивать им начальные значения при создании объекта класса.

Синтаксис инициализации членов класса аналогичен тому, который используется для вызова конструктора базового класса. Вот как выглядит общий формат такой инициализации.

 

 

Члены, подлежащие инициализации, указываются после конструктора класса, и отделяются от имени конструктора и списка его аргументов двоеточием. При этом в одном и том же списке можно смешивать обращения к конструкторам базового класса с инициализацией членов.

Ниже представлена предыдущая программа, но переделанная так, чтобы члены numA и numB были объявлены с использованием модификатора const , и получали свои начальные значения с помощью альтернативного синтаксиса инициализации членов класса.

 

 

Эта программа генерирует такие же результаты, как и ее предыдущая версия. Однако обратите внимание на то, как инициализированы члены numA и numB .

 

 

Здесь член numA инициализируется значением, переданным в аргументе х , а член numB – значением, переданным в аргументе у . И хотя члены numA и numB сейчас определены как const ‑переменные, они могут получить свои начальные значения при создании объекта класса myclass , поскольку здесь используется альтернативный синтаксис инициализации членов класса.

 

Использование ключевого слова asm

 

С помощью ключевого слова asm в С++‑программу встраивается код, написанный на языке ассемблера.

Несмотря на то что C++ – всеобъемлющий и мощный язык программирования, возможны ситуации, обработка которых для него оказывается весьма затруднительной. (Например, в C++ не предусмотрена инструкция, которая могла бы запретить прерывания.) Чтобы справиться с подобными специальными ситуациями, C++ предоставляет средство, которое позволяет войти в код, написанный на языке ассемблера, совершенно игнорируя С++‑компилятор. Этим средством и является инструкция asm , используя которую можно встроить ассемблерный код непосредственно в С++‑программу. Этот код скомпилируется без каких‑либо изменений и станет частью кода вашей программы, начиная с места нахождения инструкции asm .

Общий формат использования ключевого слова asm имеет следующий вид.

 

 

Здесь элемент код означает инструкцию, написанную на языке ассемблера, которая будет встроена в программу. При этом некоторые компиляторы также позволяют использовать и другие форматы записи инструкции asm.

 

 

Здесь элемент инструкция означает любую допустимую инструкцию языка ассемблера. Поскольку использование инструкции asm зависит от конкретной реализации среды программирования, то за подробностями обратитесь к документации, прилагаемой к вашему компилятору.

На момент написания этой книги в среде Visual C++ (Microsoft) для встраивания кода, написанного на языке ассемблера, предлагалось использовать инструкцию _ _asm . Во всём остальном этот формат аналогичен описанию инструкции asm .

Осторожно! Для использования инструкции asm необходимо обладать доскональными знаниями языка ассемблера. Если вы не считаете себя специалистом по этому языку, то лучше пока избегать использования инструкции asm, поскольку неосторожное ее применение может вызвать тяжелые последствия для вашей системы.

 

Спецификация компоновки

 

Спецификатор компоновки позволяет определить способ компоновки функции .

В C++ можно определить, как функция связывается с вашей программой. По умолчанию функции компонуются как С++‑функции. Но, используя спецификацию компоновки, можно обеспечить компоновку функций, написанных на других языках программирования. Общий формат спецификатора компоновки выглядит так:

 

 

Здесь элемент язык означает нужный язык программирования. Все С++‑компиляторы поддерживают как С‑, так и С++‑компоновку. Некоторые компиляторы также позволяют использовать спецификаторы компоновки для таких языков, как Fortran , Pascal или BASIC . (Эту информацию необходимо уточнить в документации, прилагаемой к вашему компилятору.)

Следующая программа позволяет скомпоновать функцию myCfunc() как С‑функцию.

 

 

На заметку. Ключевое слово extern – необходимая составляющая спецификации компоновки. Более того, спецификация компоновки должна быть глобальной; ее нельзя использовать в теле какой‑либо функции.

Используя следующий формат спецификации компоновки, можно задать не одну, а сразу несколько функций.

 

 

Спецификации компоновки используются довольно редко, и вам, возможно, никогда не придется их применять. Основное их назначение – позволить применение в С++‑программах кода, написанного сторонними организациями на языках, отличных от C++.

 

Операторы указания на члены ".*" и "‑>*"

 

Операторы указания на член позволяют получить доступ к члену класса через указатель на этот член.

В C++ предусмотрена возможность сгенерировать указатель специального типа, который "ссылается" не на конкретный экземпляр члена в объекте, а на член класса вообще. Указатель такого типа называется указателем на член класса (pointer‑to‑member). Это – не обычный С++‑указатель. Этот специальный указатель обеспечивает только соответствующее смещение в объекте, которое позволяет обнаружить нужный член класса. Поскольку указатели на члены – не настоящие указатели, к ним нельзя применять операторы "." и "‑>" . Для получения доступа к члену класса через указатель на член необходимо использовать специальные операторы ".*" и "‑>*" .

Если идея, изложенная в предыдущем абзаце, вам показалась немного "туманной" , то следующий пример поможет ее прояснить. При выполнении этой программы отображается сумма чисел от 1 до 7 . Здесь доступ к членам класса myclass (функции sum_it() и переменной sum ) реализуется путем использования указателей на члены.

 

 

Результат выполнения этой программы таков.

 

 

В функции main() создается два члена‑указателя: dp (для указания на переменную sum) и fp (для указания на функцию sum_it()). Обратите внимание на синтаксис каждого объявления. Для уточнения класса используется оператор разрешения контекста (оператор разрешения области видимости). Программа также создает объект типа myclass с именем с .

Затем программа получает адреса переменной sum и функции sum_it() и присваивает их указателям dp и fp соответственно. Как упоминалось выше, эти адреса в действительности представляют собой лишь смещения в объекте типа myclass , по которым можно найти переменную sum и функцию sum_it() . Затем программа использует указатель на функцию fp , чтобы вызвать функцию sum_it() для объекта с . Наличие дополнительных круглых скобок объясняется необходимостью корректно применить оператор ".*" . Наконец, программа отображает значение суммы чисел, получая доступ к переменной sum объекта с через указатель dp .

При доступе к члену объекта с помощью объекта или ссылки на него необходимо использовать оператор ".*" . Но если для этого используется указатель на объект, нужно использовать оператор "‑>*" , как показано в этой версии предыдущей программы.

 

 

В этой версии переменная с объявляется как указатель на объект типа myclass , а для доступа к члену данных sum и функции‑члену sum_it() используется оператор "‑>*" .

Помните, что операторы указания на члены класса предназначены для специальных случаев, и их не стоит использовать для решения обычных повседневных задач программирования.

 


Дата добавления: 2018-09-22; просмотров: 302; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!