Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ | страница 63
>// управления ресурсом
>bool taxable2 = !((*pi2).isTaxFree()); // доступ к ресурсу
>// через оператор *
>...
Поскольку иногда необходимо получать доступ к ресурсу, управляемому RAII-объектом, то некоторые реализации RAII предоставляют функции для неявного преобразования. Например, рассмотрим следующий класс для работы со шрифтами, инкапсулирующий «родной» интерфейс, написанный на C:
>FontHandle getFont(); // из С API – параметры пропущены
>// для простоты
>void releaseFont(FontHandle fh); // из того же API
>class Font { // класс RAII
>public:
>explicit Font(FontHandle fh) // захватить ресурс:
>:f(fh) // применяется передача по значению,
>{} // потому что того требует C API
>~Font() {releaseFont(f);} // освободить ресурс
>private:
>FontHandle f; // управляемый ресурс – шрифт
>};
Предполагается, что есть обширный программный интерфейс, написанный на C, работающий исключительно в терминах FontHandle. Поэтому часто приходится преобразовывать объекты из типа Font в FontHandle. Класс Font может предоставить функцию явного преобразования, например get:
>class Font {
>public:
>...
>FontHandle get() const {return f;} // функция явного преобразования
>...
>};
К сожалению, пользователю придется вызывать get всякий раз при взаимодействии с API:
>void changeFontSize(FontHandle f, int newSize); // из C API
>Font f(getFont());
>int newFontSize;
>...
>changeFontSize(f.get(), newFontSize); // явное преобразование
>// из Font в FontHandle
Некоторые программисты могут посчитать, что каждый раз выполнять явное преобразование настолько обременительно, что вообще откажутся от применения этого класса. В результате возрастет опасность утечки шрифтов, а именно для того, чтобы предотвратить это, и был разработан класс Font.
Альтернативой может стать предоставление классом Font функции неявного преобразования к FontHandle:
>class Font {
>public:
>...
>operator FontHandle() const // функция неявного преобразования
>{return f;}
>...
>};
Это сделает вызовы C API простыми и естественными:
>Font f(getFont());
>int newSize;
>...
>changeFontSize(f, newFontSize); // неявное преобразование из Font
>// в FontHandle
Увы, у этого решения есть и оборотная сторона: повышается вероятность ошибок. Например, пользователь может нечаянно создать объект FontHandle, имея в виду Font:
>Font f1(getFont());
>...
>FontHandle f2 = f1; // Ошибка! Предполагалось скопировать объект Font,
>// а вместо f1 неявно преобразован в управляемый
>// им FontHandle, который и скопирован в f2
Теперь в программе есть FontHandle, управляемый объектом Font f1, однако он же доступен и напрямую, как f2. Это почти всегда нехорошо. Например, если f1 будет уничтожен, шрифт освобождается, и f2 становится «висячей ссылкой».