В этой статье будет рассказано:
- Замечания о функциях-членах
- Встроенные методы
- Какой объект использует метод
Мы по-прежнему обязаны определять вторую часть спецификации класса, т.е. предоставлять код для тех функций-членов, которые описаны с помощью прототипов в объявлении класса. Определения функций-членов очень похожи на определения обычных функций. Каждое из них имеет заголовок и тело. Определения функций-членов могут иметь тип возврата и аргументы. Но, кроме того, с ними связаны две специфических характеристики.
• При определении функции-члена для идентификации класса, которому
принадлежит функция, используется операция разрешения контекста (: :).
• Методы класса имеют доступ к private-компонентам класса.
Давайте рассмотрим все это подробнее.
В заголовке функции-члена для идентификации класса, которому она принадлежит, применяется операция разрешения контекста (: :). Например, заголовок для функции-члена update () выглядит следующим образом:
void Stock::update(double price)
Эта нотация означает, что вы определяете функцию update (), которая является членом класса Stock. Но это означает не только то, что функция update () является функцией-членом, но также и то, что такое же имя можно использовать для функций- членов другого класса. Например, функция update () для класса Button будет иметь следующий заголовок:
void Button::update(double price)
Таким образом, операция разрешения контекста идентифицирует класс, к
которому данный метод относится. Говорят, что идентификатор update () имеет область видимости класса. Другие функции-члены класса Stock могут при необходимости использовать метод update () без операции разрешения контекста. Это связано с тем, что они принадлежат одному классу, и, следовательно, имеют общую область видимости. Использование update () за пределами объявления класса и определений методов, однако, требует соблюдения специальных мер, которые мы рассмотрим далее.
Единственный способ однозначного разрешения имен методов — использовать полное имя, включающее имя класса. Stock: :update () называется уточненным именем функции. Простое имя update (), с другой стороны, является сокращением (неуточненным именем) полного имени и может применяться только в контексте класса.
Следующей специальной характеристикой методов является то, что метод может
иметь доступ к закрытым членам класса. Например, метод show () может использовать
код вроде следующего:
cout « "Company: " « company
« " Shares: " « shares « endl
<< " Share Price: $" « share_val
« " Total Worth: $" « total_val « endl;
Здесь company, shares и т.д. являются закрытыми данными-членами класса Stock. Если вы попытаетесь воспользоваться для доступа к этим данным-членам функцией, которая не является членом, то компилятор воспрепятствует этому.
Памятуя об этих двух обстоятельствах, методы класса можно реализовать, как показано в программе ниже. Эти определения методов могут быть помещены в отдельный файл либо в тот же файл, где находится объявление класса. Мы поместили их в отдельный файл реализации, поэтому в нем потребуется включить заголовочный файл stockOO. h, чтобы компилятор имел доступ к определению класса. Для демонстрации возможности работы с пространствами имен в одних методах используется квалификатор std: :, а в других — объявления using.
*знак решетки*include <iostream>
*знак решетки*include "stockOO.h"
void Stock:racquire(const std::string & со, long n, double pr)
{
company = со;
if (n < 0)
{
// Количество пакетов не может быть отрицательным; устанавливается в 0.
std::cout « "Number of shares can't be negative; "
« company « " shares set to 0.\n";
shares = 0;
}
else
shares = n;
share_val = pr;
set_tot();
}
void Stock::buy(long num, double price)
{
if (num < 0)
{
//Количество приобретаемых пакетов не может быть отрицательным. Транзакция прервана.
std::cout « "Number of shares purchased can't be negative. "
« "Transaction is aborted.\n";
}
else
{
shares += num;
share_val = price;
set_tot();
}
}
void Stock::sell(long num, double price)
{
using std::cout;
if (num < 0)
{
// Количество продаваемых пакетов не может быть отрицательным. Транзакция прервана,
cout « "Number of shares sold can't be negative. "
« "Transaction is aborted.\n";
}
else if (num > shares)
{
// Нельзя продать больше того, чем находится во владении. Транзакция прервана,
cout « "You can't sell more than you have! "
« "Transaction is aborted.\n";
}
else
{
shares -= num;
share_val = price;
set_tot() ;
}
}
void Stock::update(double price)
{
share_val = price;
set_tot() ;
}
void Stock::show ()
{
// Вывод названия компании, количества пакетов, цены пакета и общей стоимости.
std::cout « "Company: " « company
« " Shares: " « shares « '\n'
« " Share Price: $" « share_val
« " Total Worth: $" « total_val « '\n'; л
)
Замечания о функциях-членах
Функция acquire () управляет первоначальной покупкой пакета акций заданной компании, в то время как buy() и sell() — дополнительной покупкой и продажей акций из существующего пакета. Методы buy() HsellO гарантируют, что количество купленных или проданных акций не будет отрицательным. Кроме того, если пользователь пытается продать больше акций, чем у него есть, функция sell () отменит транзакцию. Прием объявления данных закрытыми и ограничения доступа к открытым функциям предоставляет контроль над использованием данных. В данном случае это позволяет предпринять защитные меры против недопустимых транзакций.
Четыре из определенных функций-членов устанавливают или сбрасывают
значение члена totalval. Вместо того чтобы повторять в коде вычисление этого значения четыре раза, каждая из открытых функций-членов вызывает функцию settot (). Поскольку эта функция представляет собой просто реализацию внутреннего кода, а не является частью открытого интерфейса, в классе она объявлена как закрытая
функция-член. (То есть set_tot О представляет собой функцию-член, которая используется разработчиком класса, но не теми, кто пишет код, использующий класс.) Если вычисления, выполняемые функцией, оказываются сложными, это поможет также уменьшить общий объем исходного кода. Однако здесь главное в том, что за счет
использования вызова этой функции вместо повторения кода вычислений
обеспечивается гарантия того, что всегда будет применяться абсолютно идентичный алгоритм. Кроме того, если его понадобится изменить (хотя в данном конкретном случае такое маловероятно), это нужно будет сделать только в одном месте.
Встроенные методы
Любая функция с определением внутри объявления класса автоматически
становится встроенной. Это значит, что Stock: : settot () является встроенной функцией. Объявления класса часто используют встроенные функции для коротких функций-членов, и settot () — пример такого случая.
Если хотите, можете определить функцию-член вне объявления класса и, тем не менее, сделать ее встроенной. Чтобы это сделать, просто используйте квалификатор inline при определении функции в разделе реализации класса:
class Stock
{
private:
void set_tot(); // определение оставлено отдельным
public:
};
inline void Stock::set_tot() // использование inline в определении
{
total_val = shares * share_val;
}
Специальные правила для встроенных функций требуют, чтобы они были
определены в каждом файле, в котором используются. Самый простой способ гарантировать, что встроенные определения доступны всем файлам в многофайловой программе — поместить эти определения в тот же заголовочный файл, где объявлен класс. (Некоторые системы разработки снабжены интеллектуальными компоновщиками, которые разрешают размещать встроенные определения в отдельном файле реализации.)
Кстати, согласно правилу перезаписи, определение метода внутри объявления класса эквивалентно замене определения метода прототипом и последующей перезаписью определения в виде встроенной функции немедленно после объявления класса. То есть исходное определение settot () в программе выше эквивалентно только что показанному, где определение следует за объявлением класса.
Какой объект использует метод?
Мы подошли к одному из наиболее важных аспектов использования объектов: каким образом метод класса применяется к объекту. Код вроде показанного ниже использует член shares некоторого объекта:
shares += num;
Но какого объекта? Отличный вопрос! Чтобы ответить на него, давайте вначале посмотрим, как создается объект. Наиболее простой способ объявления переменных класса выглядит так:
Stock kate, joe;
Это создает два объекта класса Stock, один по имени kate, а второй — joe.
Теперь рассмотрим, как использовать функцию-член с одним из этих объектов. Ответ, как и случае структур и членов структур, состоит в применении операции членства:
kate.show(); // объект kate вызывает функцию-член
joe.show(); // объект joe вызывает функцию-член
Первый оператор вызывает show () как член объекта kate. Это значит, что
метод интерпретирует shares как kate.shares, a share_val — как kate.share_val. Аналогично вызов joe. show () заставляет метод show () интерпретировать shares как joe. shares, a share_val — как joe. share_val, соответственно.
На заметку!
Когда вы вызываете функцию-член, она использует данные-члены конкретного объекта, примененного для ее вызова.
Подобным же образом вызов kate. sell () запускает функцию settot (), как если бы это была kate.set_tot(), позволяя ей получать доступ к данным объекта kate.
Каждый вновь созданный вами объект содержит хранилище для собственных внутренних переменных-членов класса, однако все объекты одного класса разделяют общий набор методов, по одной копии каждого. Предположим, например, что kate и joe — это объекты класса Stock. В этом случае kate.shares занимает один фрагмент памяти, a joe. shares — другой. Но kate. show () и joe. show () представляют собой один и тот же метод, т.е. оба выполняют один и тот же блок кода, только применяют этот код к разным данным. Вызов функции-члена — это то, что в некоторых объектно- ориентированных языках называется отправкой сообщник. Таким образом, отправка сообщения двум разным объектам вызывает один и тот же метод, который применяется к двум разным объектам
Конец
Спасибо, если вы прочитали эту статью. Надеюсь вы что-то новое узнали для себя, и конечно же поняли. Подпишитесь, поставьте лайк, напишите комментарий, поддержите меня. Хотелось бы увидеть как улучшать статьи и чего не хватает. Буду анализировать и улучшать контент. Еще раз спасибо, до свидания! :)
#ооп #c++ #языкипрограммирования #классы #структура #компилятор #разработка #программирование #программа #интерфейс