|
Программирование >> Оптимизация возвращаемого значения
принадлежат к наиболее знающим, и, вероятно, поэтому объект string, включенный ими в библиотеку, не допускает неявного приведения от типа string к char*. Вместо этого существует функция-член c str, выполняющая данное преобразование. Совпадение? Думаю, нет. С неявным преобразованием, выполняемым конструктором с единственным аргументом, бороться труднее. Более того, проблемы, создаваемые такими конструкторами, зачастую серьезнее, чем те, которые возникают из-за операторов неявного преобразования типа. В качестве примера рассмотрим шаблон класса для массивов. Эти массивы позволяют определять верхнюю и нижнюю границы индексов: template<class Т> class Array { public: Array (int lowBound, inthighBound) ; Array(intsize); T&operator[] (intindex); Первый конструктор позволяет клиенту задавать диапазон индексов массива, например от 10 до 20. Так как у него два аргумента, то эта функция не может быть использована для преобразования типа. Напротив, с помощью второго конструктора допускается создавать объекты Array, указывая только количество элементов в массиве (так же, как это делается для встроенных массивов). Он может быть использован для преобразования типов, и потому является источником постоянного раздражения. Рассмотрим реализацию сравнения объектов Array<int> и пример обработки таких объектов: booloperator==(constArray<int>&Ihs, constArray<int>&rhs); Array<int>a(10); Array<int>b(10); for (int i=0; i<10; ++i) if(a==b[i]){ Вместо а должно быть a [ i] . / / Если a [ i ] и b [ i ] равны, выполнить какие-тодействия. else { выполнить другие действия, есш они не равны; } Мы намеревались сравнить элементы а с соответствующими элементами Ь, но сл5айно пропустили индекс при а. Конечно, хотелось бы, чтобы эта ошибка вызвала у компиляторов поток нелицеприятных комментариев, но они не будут жаловаться, поскольку встретят вызов operator== с аргументами типа Array<int> (для a) и int (для b). И хотя operator== с аргументами такого типа не определен, компиляторы заметят, что они могут преобразовать int в объект типа Аггау< int >, вызвав конструктор Array<int>, принимающий int в качестве единственного аргумента. Именно это они и сделают, создав код, который явно не предполагался: for (int i = 0; i<10; + + i) if (a==static cast<Array<int (b[i] ) ) . . . Ha каждом шаге цикла программа сравнивает содержимое а с содержимым временного массива размерности b [ i ] (содержимое которого, скорее всего, не определено). Эта программа не только некорректна, но и крайне неэффективна, потому что на каждом шаге создает и удаляет временный объект Array<int> (см. правило 19). Проблем, возникающих из-за операторов неявного преобразования типа, можно избежать, если просто не объявлять эти операторы, но для конструкторов с единственным аргументом такой подход неприемлем. Данные конструкторы могут быть действительно нужны клиентам. В то же время нельзя и позволять компиляторам вызывать эти конструкторы без разбора. К счастью, существует возможность удовлетворить оба требования. Есть даже два пути: простой и тот, которым вам придется пользоваться, если ваши компиляторы пока не поддерживают первый путь. Простой вариант состоит в использовании одной из новых черт С++, а именно ключевого слова explicit. Эта особенность была специально введена для решения проблемы неявного преобразования типов, и ее применение предельно облегчено. Если конструктор объявлен с атрибутом explicit, то компиляторам запрещается вызывать его для неявного преобразования типа, в то время как явное преобразование разрешено: template<class Т> class Array { public: explicit Array(intsize); Использование explicit. Array<int>a(10); Нормально, конструктор, объявленный как explicit, / / может быть использован / / для создания объектов. Array<int>b(10); Также нормально. if(a==b[i]) ... Ошибка!Невозможно неявно преобразовать int / / BArray<int>. if (a==Array<int>(b[i] ) ) ... Нормально, явное преобразование типа от int BArray<int> разрешено (хотя логика / / программы и выглядит подозрительно). if {a==static cast<ArraY<int>>(b[i])) . . . / / Также нормально, / / логика подозрительна. if {а== {ArraY<int>)b[i] ) . . . Преобразования / / в стиле С также разрешены, / / но программа продолжает оставаться подозрительной. В примере, использующем static cast (см. правило 2), пробел, разделяющий два знака >, неслучаен. Если бы выражение было написано следующим образом: if {a==static cast<Array<int {b[i]) ) .. . оно имело бы другой смысл. Это вызвано тем, что компиляторы С++ рассматривают выражение как единую конструкцию. Без пробела между символами > выражение породило бы синтаксическую ошибку. Если ваши компиляторы пока не поддерживают explicit, вам придется освоить приемы, которые предотвращают использование конструкторов с одним аргументом в качестве функций неявного преобразования типа. Чтобы понять эти методы, достаточно увидеть их хотя бы один раз. Ранее я упоминал, что правила, по которым определяется, какие последовательности неявного преобразования типа корректны, а какие нет, довольно сложны. Одно из этих правил состоит в том, что последовательность преобразований не может содержать более одного преобразования, определенного пользователем (то есть вызова конструктора с единственным аргументом или оператора неявного преобразования типа). Правильно сконструировав классы, нетрудно использовать это правило таким образом, чтобы создание объектов было разрешено, а нежелательные неявные преобразования типов оказались запрещены. Снова рассмотрим шаблон Array. Допустим, требуется разработать способ, который бы разрешал передавать конструктору целочисленный размер массива в качестве аргумента и в то же время запрещал неявное преобразование целых чисел во временный объект Array. Сначала создается новый класс ArraySize. Объекты этого типа служат единственной цели: они описывают размерность массива, который будет создан. Затем конструктор с одним аргументом Array переписывается так, чтобы принимать в качестве аргумента ArraySize, а не int. Исходный текст выглядит следующим образом: template<class Т> class Array { public: class ArraySize{ Новыйкласс.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |