Найти в Дзене

Реализация функций-членов класса в C++

В этой статье будет рассказано:

  • Замечания о функциях-членах
  • Встроенные методы
  • Какой объект использует метод

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

• При определении функции-члена для идентификации класса, которому

принадлежит функция, используется операция разрешения контекста (: :).

• Методы класса имеют доступ к 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 () представляют собой один и тот же метод, т.е. оба выполняют один и тот же блок кода, только применяют этот код к разным данным. Вызов функции-члена — это то, что в некоторых объектно- ориентированных языках называется отправкой сообщник. Таким образом, отправка сообщения двум разным объектам вызывает один и тот же метод, который применяется к двум разным объектам

-2

Конец

Спасибо, если вы прочитали эту статью. Надеюсь вы что-то новое узнали для себя, и конечно же поняли. Подпишитесь, поставьте лайк, напишите комментарий, поддержите меня. Хотелось бы увидеть как улучшать статьи и чего не хватает. Буду анализировать и улучшать контент. Еще раз спасибо, до свидания! :)

#ооп #c++ #языкипрограммирования #классы #структура #компилятор #разработка #программирование #программа #интерфейс

Наука
7 млн интересуются