Категории
Самые читаемые
Лучшие книги » Компьютеры и Интернет » Программирование » Язык программирования C++. Пятое издание - Стенли Липпман

Язык программирования C++. Пятое издание - Стенли Липпман

Читать онлайн Язык программирования C++. Пятое издание - Стенли Липпман

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 84 85 86 87 88 89 90 91 92 ... 297
Перейти на страницу:

Как уже упоминалось, у класса будут также две функции-члена, combine() и isbn(). Кроме того, предоставим классу Sales_data другую функцию-член, чтобы возвращать среднюю цену, по которой были проданы книги. Эта функция, назовем ее avg_price(), не предназначена для общего использования. Она будет частью реализации, а не интерфейса.

Функции-члены определяют (см. раздел 6.1) и объявляют (см. раздел 6.1.2) как обычные функции. Функции-члены должны быть объявлены в классе, но определены они могут быть непосредственно в классе или вне тела класса. Функции, не являющиеся членами класса, но являющиеся частью интерфейса, как функции add(), read() и print(), объявляются и определяются вне класса.

С учетом вышеизложенного напишем пересмотренную версию класса Sales_data:

struct Sales_data {

 // новые члены: операции с объектами класса Sales_data

 std::string isbn() const { return bookNo; }

 Sales_data& combine(const Sales_data&);

 double avg_price() const;

 // те же переменные-члены, что и в p. 2.6.1

 std::string bookNo;

 unsigned units_sold = 0;

 double revenue = 0.0;

};

// функции интерфейса класса Sales_data, не являющиеся его членами

Sales_data add(const Sales_data&, const Sales_data&);

std::ostream &print(std::ostream&, const Sales_data&);

std::istream &read(std::istream&, Sales_data&);

Функции, определенные в классе, неявно являются встраиваемыми (см. раздел 6.5.2).

Определение функций-членов

Хотя каждый член класса должен быть объявлен в самом классе, тело функции-члена можно определить либо в, либо вне тела класса. Функция isbn() определяется в классе Sales_data, а функции combine() и avg_price() вне его.

Сначала рассмотрим функцию isbn(), возвращающую строку и имеющую пустой список параметров:

std::string isbn() const { return bookNo; }

Как и у любой функции, тело функции-члена является блоком. В данном случае блок содержит один оператор return, возвращающий значение переменной-члена bookNo объекта класса Sales_data. Интересно, как эта функция получает объект, член bookNo которого следует выбрать?

Указатель this

Давайте снова рассмотрим вызов функции-члена isbn():

total.isbn()

Здесь для вызова функции-члена isbn() объекта total используется точечный оператор (см. раздел 4.6).

За одним исключением, рассматриваемым в разделе 7.6, вызов функции-члена осуществляется от имени объекта. Когда функция isbn() обращается к члену класса Sales_data (например, bookNo), она неявно обращается к членам того объекта, из которого была вызвана. В этом вызове функции isbn(), когда она возвращает значение члена bookNo, речь идет о члене total.bookNo.

Функция-член способна обратиться к тому объекту, из которого она была вызвана, благодаря дополнительному неявному параметру this. Когда происходит вызов функции-члена, указатель this инициализируется адресом объекта, из которого была вызвана функция. Рассмотрим следующий вызов:

total.isbn()

Здесь компилятор присваивает адрес объекта total указателю this и неявно передает его как параметр функции isbn(). Компилятор как бы переписывает этот вызов так:

// псевдокод, в который преобразуется вызов функции-члена

Sales_data::isbn(&total)

Этот код вызывает функцию-член isbn() класса Sales_data, передав адрес объекта total.

В функции-члене можно обратиться непосредственно к членам объекта, из которого она была вызвана. Для использования членов объекта, на который указывает указатель this, можно не использовать оператор доступа к члену. Любое непосредственное использование члена класса подразумевает использование указателя this. Таким образом, когда функция isbn() использует переменную bookNo, она неявно использует член объекта, на который указывает указатель this. Это аналогично синтаксису this->bookNo.

Параметр this определяется неявно и автоматически. Кроме того, определить параметр или переменную по имени this самому нельзя, но в теле функции-члена его использовать можно. Вполне допустимо, хоть и не нужно, определить функцию isbn() так:

std::string isbn() const { return this->bookNo; }

Поскольку указатель this всегда предназначен для обращения к "этому" объекту, он является константным (см. раздел 2.4.2). Нельзя изменить адрес, хранящийся в указателе this.

Константные функции-члены

Еще одним важным моментом функции-члена isbn() является ключевое слово const, расположенное за списком параметров. Оно применяется для модификации типа неявного указателя this.

По умолчанию указатель this имеет тип константного указателя на неконстантную версию типа класса. Например, типом по умолчанию указателя this в функции-члене Sales_data является Sales_data *const. Хоть указатель this и неявен, он подчиняется обычным правилам инициализации, согласно которым (по умолчанию) нельзя связать указатель this с константным объектом (см. раздел 2.4.2). Следствием этого факта, в свою очередь, является невозможность вызвать обычную функцию-член для константного объекта.

Если бы функция isbn() была обычной и если бы указатель this был обычным параметром типа указателя, то мы объявили бы его как const Sales_data *const. В конце концов, тело функции isbn() не изменяет объект, на который указывает указатель this; таким образом, эта функция стала бы гибче, если бы указатель this был указателем на константу (см. раздел 6.2.3).

Однако указатель this неявный и не присутствует в списке параметров, поэтому нет места, где можно было бы указать, что он должен быть указателем на константу. Язык решает эту проблему, позволяя разместить ключевое слово const после списка параметров функции-члена. Это означает, что указатель this является указателем на константу. Функции-члены, использующие ключевое слово const таким образом, являются константными функциями-членами (const member function).

Тело функции isbn() можно считать написанным так:

// псевдокод, иллюстрирующий использование неявного указателя

// этот код недопустим: нельзя самому явно определить этот указатель

// обратите внимание, что это указатель на константу, поскольку isbn()

// является константным членом класса

std::string Sales_data::isbn(const Sales_data *const this)

{ return this->isbn; }

Тот факт, что this является указателем на константу, означает, что константные функции-члены не могут изменить объект, для которого они вызваны. Таким образом, функция isbn() может читать значения переменных- членов объектов, для которых она вызывается, но не изменять их.

Константные объекты, ссылки и указатели на константные объекты могут вызывать только константные функции-члены

Область видимости класса и функции-члены

Помните, что класс сам является областью видимости (см. раздел 2.6.1). Определения функций-членов класса находятся в области видимости самого класса. Следовательно, использованное функцией isbn() имя bookNo относится к переменной-члену, определенной в классе Sales_data.

Следует заметить, что функция isbn() может использовать имя bookNo, несмотря на то, что оно определено после функции isbn(). Как будет описано в разделе 7.4.1, компилятор обрабатывает классы в два этапа — сначала объявления членов класса, затем тела функций-членов, если таковые вообще имеются. Таким образом, тела функций-членов могут использовать другие члены своих классов, независимо от того, где именно в классе они определены.

Определение функции-члена вне класса

Подобно любой другой функции, при определении функции-члена вне тела класса ее определение должно соответствовать объявлению. Таким образом, тип возвращаемого значения, список параметров и имя должны совпадать с объявлением в теле класса. Если член класса был объявлен как константная функция, то в определении после списка параметров также должно присутствовать ключевое слово const. Имя функции-члена, определенное вне класса, должно включить имя класса, которому она принадлежит:

double Sales_data::avg_price() const {

 if (units_sold)

  return revenue/units_sold;

 else

  return 0;

}

Имя функции, Sales data::avg_price(), использует оператор области видимости (см. раздел 1.2), чтобы указать, что определяемая функция по имени avg_price объявлена в пределах класса Sales_data. Как только компилятор увидит имя функции, остальная часть кода интерпретируется как относящаяся к области видимости класса. Таким образом, когда функция avg_price() обращается к переменным revenue и units_sold, она неявно имеет в виду члены класса Sales_data.

1 ... 84 85 86 87 88 89 90 91 92 ... 297
Перейти на страницу:
На этой странице вы можете бесплатно скачать Язык программирования C++. Пятое издание - Стенли Липпман торрент бесплатно.
Комментарии