Чтение онлайн

на главную - закладки

Жанры

C++. Сборник рецептов

Когсуэлл Джефф

Шрифт:

bool RecordSet::getFieldVal(int i, std::string& s) const {

 fieldArray_[i] = s; // Ой, я не это имел в виду

 // ...

}

Снова компилятор преждевременно завершит работу и выдаст сообщение об ошибке, потому что вы пытаетесь изменить переменную-член, а это не разрешается делать в константных функциях-членах. Ну, при одном исключении.

В классе

RecordSet
(в таком, как (схематичный) класс в примере 15.4) вам, вероятно, потребовалось бы перемещаться туда-сюда по набору записей, используя понятие «текущей» записи. Простой способ заключается в применении переменной-члена
целого типа, содержащей номер текущей записи; ваши функции-члены, предназначенные для перемещения текущей записи вперед-назад, должны увеличивать или уменьшать это значение.

void RecordSet::gotoNextPecord const {

 if (curIndex_ >= 0 && curIndex_ < numRecords_-1)

++curIndex_;

}

void RecordSet::gotoPrevRecord const {

 if (curIndex_ > 0)

– -curIndex_;

}

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

RecordSet
не смогут перемещаться по объекту
const RecordSet
. Это исключение из правил работы с константными функциями-членами является вполне разумным, поэтому C++ имеет механизм его поддержки: ключевое слово
mutable
.

Для того чтобы

curIndex_
можно было обновлять в константной функции-члене, объявите ее с ключевым словом mutable в объявлении класса.

mutable int curIndex_;

Это позволит вам модифицировать

curIndex_
в любом месте. Однако этой возможностью следует пользоваться разумно, поскольку это действует на вашу функцию так, как будто она становится с этого момента неконстантной.

Применение ключевого слова

const
в примере 15.4 позволяет гарантировать невозможность изменения состояния объекта в функции-члене. В целом, такой подход дает хорошие результаты, потому что сообщает пользователям класса о режиме работы функции-члена и потому что сохраняет вам репутацию, заставляя компилятор проконтролировать отсутствие в функции-члене непредусмотренных действий.

15.5. Написание оператора, не являющегося функцией-членом

Проблема

Необходимо написать бинарный оператор, и вы не можете или не хотите сделать его функцией-членом класса.

Решение

Используйте ключевое слово

operator
, временную переменную и конструктор копирования для выполнения основной работы и возвратите временный объект. В примере 15.5 приводится простой оператор конкатенации строк для пользовательского класса
String
.

Пример 15.5. Конкатенация с использованием оператора не члена

#include <iostream>

#include <cstring>

class String { // Предположим, что объявление класса String содержит,

// по крайней мере, все, что указанно ниже

public:

 String;

 String(const char* p);

 String(const String& orig);

 ~String {delete buf_;}

 String& append(const String& s);

 size_t length const;

 const char* data const;

 String& operator=(const String& orig);

 // ...

};

String operator+(const String& lhs, const String& rhs) {

 String tmp(lhs); //
Сконструировать временный объект с помощью

// конструктора копирования

 tmp.append(rhs); // Использовать функцию-член для выполнения реальной

// работы

 return(tmp); // Возвратить временный объект

}

int main {

 String s1("banana ");

 String s2("rancher");

 String s3, s4, s5, s6;

 s3 = s1 + s2; // Работает хорошо, но с сюрпризами

 s4 = s1 + "rama"; // Автоматически конструируется "rama", используя

// конструктор String(const char*)

 s5 = "ham " + s2; // Круто, то же самое можно делать даже

 s6 = s1 + "rama " + s2; // с другим операндом

 std::cout << "s3 = " << s3.data << '\n';

 std::cout << "s4 = " << s4.data << '\n';

 std::cout << "s5 = " << s5.data << '\n';

 std::cout << "s6 = " << s6.data << '\n';

}

Обсуждение

Независимый оператор объявляется и определяется подобно оператору функции-члена. В примере 15.5 я мог бы реализовать

operator+
как функцию-член, объявляя ее следующим образом.

String operator+(const String& rhs);

В большинстве случаев это будет работать одинаково, независимо от того, определяется ли

operator+
как функция-член или нет, однако существует, по крайней мере, две причины, по которым желательно реализовать его не как функцию-член. Первая причина концептуальная, имеет ли смысл иметь оператор, который возвращает новый, отличный от других объект?
operator+
, реализованный как функция-член, не проверяет и не изменяет состояние объекта. Это служебная функция общего назначения, которая в данном случае работает со строками типа
String
и, следовательно, не должна являться функцией членом.

Вторая причина техническая. При использовании оператора-члена вы не сможете выполнить следующую операцию (из приведенного выше примера).

s5 = "ham " + s2;

Это не сработает, потому что символьная строка не имеет

operator+
, который принимает
String
в качестве параметра. С другой стороны, если вы определили независимый
operator+
, который принимает два параметра типа
String
, ваш компилятор проверит наличие в классе
String
конструктора, принимающего
const char*
в качестве аргумента (или любой другой тип, который вы используете совместно с
String
), и сконструирует временный объект на этапе выполнения. Поэтому приведенная выше строка эквивалентна следующей.

Поделиться:
Популярные книги

Темный Лекарь 5

Токсик Саша
5. Темный Лекарь
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Темный Лекарь 5

Охота на разведенку

Зайцева Мария
Любовные романы:
современные любовные романы
эро литература
6.76
рейтинг книги
Охота на разведенку

Неудержимый. Книга XVI

Боярский Андрей
16. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга XVI

Газлайтер. Том 18

Володин Григорий Григорьевич
18. История Телепата
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Газлайтер. Том 18

Ищу жену для своего мужа

Кат Зозо
Любовные романы:
любовно-фантастические романы
6.17
рейтинг книги
Ищу жену для своего мужа

На границе империй. Том 8. Часть 2

INDIGO
13. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 8. Часть 2

По воле короля

Леви Кира
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
По воле короля

Черный Маг Императора 9

Герда Александр
9. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 9

Последняя Арена 8

Греков Сергей
8. Последняя Арена
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Последняя Арена 8

Измена. Вторая жена мужа

Караева Алсу
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Вторая жена мужа

Возмездие

Злобин Михаил
4. О чем молчат могилы
Фантастика:
фэнтези
7.47
рейтинг книги
Возмездие

Выстрел на Большой Морской

Свечин Николай
4. Сыщик Его Величества
Детективы:
исторические детективы
полицейские детективы
8.64
рейтинг книги
Выстрел на Большой Морской

Ты - наша

Зайцева Мария
1. Наша
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Ты - наша

Повелитель механического легиона. Том III

Лисицин Евгений
3. Повелитель механического легиона
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Повелитель механического легиона. Том III