Работа с указателем this

Функции-элементы типа const

Рассмотрим следующие фрагменты программного кода:

const Stock land=Stock("Kludgehorn Properties");

land.show();

В рассматриваемой версии C++ компилятор отвер­гает вторую строку. Почему? Да потому, что код функ­ции show() не дает гарантии, что не будет моди­фицирован вызывающий объект, который, будучи объявленным как const, не должен подвергаться изме­нениям. Все, что необходимо в таких случаях, — это новое син­таксическое средство, которое гарантирует, что функция не внесет изменений в вызывающий ее объект. В C++ эта проблема решается с помощью ключевого слова const, которое ставится после скобок функции. Други­ми словами, объявление show() принимает такой вид:

void show()const; //обещает не вносить изменений в вызывающий объект

Аналогично начальная часть определения функции принимает такой вид:

void stock::show()const // обещает не вносить изменений в вызывающий объект

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

 

Работа с указателем this

 

Продолжим работу с классом Stock. До сих пор каждая функция-элемент этого класса имела дело с одним-единственным объектом. Этим объектом был объект, который обращался к ней. Однако иногда возникает потребность в методе, который работает с двумя объектами, и эта задача решается с использованием специального указа­теля C++, получившего имя this.

Несмотря на то, что объявление класса Stock отобра­жает данные, ему не хватает аналитических возможнос­тей. Например, проанализировав выходные данные фун­кции show(), вы сможете сказать, какой из ваших вкладов превосходит по величине все остальные. Одна­ко программа этого сделать не может, поскольку у нее нет непосредственного доступа к значению total_val.

Воспользу­емся подходом, позволяющим изучить указатель this. Этот подход состоит в том, что определяется функция-эле­мент, которая просматривает два объекта Stock и воз­вращает ссылку на тот из них, который больше по ве­личине. При попытке реализовать этот подход возникает ряд вопросов.

Во-первых, как будет выглядеть функция-элемент, выполняющая сравнение двух объектов? Предположим, например, что вы решили назвать такой метод topval(). Далее, при вызове функции stockl.topvaI() обеспечива­ется доступ к данным объекта stock1, в то время как сообщение stock2.topval() получает доступ к данным объекта stock2. Если вы хотите, чтобы указанный выше метод провел сравнение двух объектов, то необходимо передать второй объект как аргумент. В целях повыше­ния производительности передайте этот аргумент по ссылке. Иначе говоря, пусть метод topval() использует аргумент типа const Stock&.

Во-вторых, как вы возвратите ответ этого метода в вызывающую программу? Наиболее простой способ: заставить метод возвратить ссылку на объект, который имеет наибольшую общую стоимость. Таким образом, метод, выполняющий сравнение, должен иметь следую­щий прототип:

const Stock & topval(const Stock & s) const;

Эта функция осуществляет неявный доступ к одно­му из объектов, к другому объекту она получает прямой доступ, при этом она возвращает ссылку на один из двух объектов. Ключевое слово const в круглых скобках оз­начает, что функция не вносит изменений в объект, к которому она получает прямой доступ, а ключевое сло­во const, которое следует сразу за скобками, означает, что функция не подвергает модификации объект, к ко­торому она осуществляет неявный доступ. Поскольку функция возвращает ссылку на один из объектов const, возвращаемый тип также имеет ссылку const.

Предположим далее, что вы хотите сравнить объек­ты stockl и stock2 класса Stock и присвоить тот из них, который имеет большую общую стоимость, объекту top. Для этого можно воспользоваться любым из следующих двух операторов:

top = stockl.topval(stock2);

top = stock2.topval(stockl);

Первый из них получает прямой доступ к объекту stockl и неявный доступ к объекту stock2, в то время как второй получает прямой доступ к объекту stockl и не­явный доступ к объекту stock2.

Каким бы ни был доступ, этот метод сравнивает два объекта и возвращает ссылку на тот из них, у которого общая стоимость больше.

Между тем, мы еще не все выяснили из того, как реа­лизовать функцию topval(). При этом возникает небольшая проблема. Ниже представлена частичная реализация, ко­торая позволяет нам вникнуть в суть этой проблемы.

const Stock & Stock::topval(const Stock & s) const

{

if (s.total_val > total_yal)

return s; //аргумент типа объект

else

return ?????; //объект, вызывающий метод topval

}

Здесь s.total_val — это общее значение для объекта, переданного в качестве аргумента, a total_val — общее значение для объекта, которому было отправлено сооб­щение. Если значение s.total_val больше значения total_val, то функция возвращает s. В противном случае она возвращает объект, использованный для вызова ме­тода. (В среде ООП говорят, что это объект, которому передается сообщение topval.) Проблема заключается в том, как назвать этот объект? Если вы присвоите ему имя stockl.topval(stock2), то s будет ссылкой на stock2 (т.е. псевдоним для stock2), однако псевдонима у stockl нет.

В C++ эта проблема решается путем использования специального указателя this. Указатель this ссылается на объект, который используется для вызова функции-эле­мента. (По существу, указатель this передается как скры­тый аргумент рассматриваемого метода.) Следовательно, при вызове функции stockl.topval(stock2) устанавлива­ется указатель this на адрес объекта stockl и обеспечи­вается доступ к этому указателю со стороны метода topval(). Аналогично при вызове функции stock2.topval(stockl) устанавливается указатель this на адрес объекта stock2. В общем случае для всех методов класса указатель this указывает на адрес объекта, кото­рый вызывает этот метод. И в самом деле, total_val в методе topval() — всего лишь сокращенное обозначение от this->totaI_val. (Напомним, что вы пользо­вались оператором -> для доступа к элементам структур посредством указателя. То же самое справедливо и для элементов класса.)

УКАЗАТЕЛЬ THIS

Каждая функция-элемент, включая конструкторы и дест­рукторы, имеет указатель this. Характерной особенностью указателя this является то, что он указывает на вызываю­щий объект. Если у какого-либо метода возникает необ­ходимость ссылки на объект как на единое целое, он может воспользоваться выражением *this. Спецификатор const, помещенный сразу за скобками, в которые заклю­чены аргументы, истолковывает в рассматриваемом слу­чае указатель this как const; в такой ситуации вы не може­те использовать this, чтобы изменить значение объекта.

 

Однако то, что вы хотите возвратить, — это вовсе не указатель this, так как this выражает адрес объекта. Вы же хотите вернуть сам объект, а он обозначается как *this. (Напомним, что в результате применения опера­тора разыменования * к указателю получается величи­на, на которую указывает указатель.) Теперь вы можете завершить определение метода, используя *this как псев­доним вызывающего объекта.

const Stock & Stock::topval(const Stock & s) const

{

if (s.total_val > total_val)

return s; //объект в качестве аргумента else

return *this; //вызывающий объект

}

Тот факт, что возвращаемый тип является ссылкой, означает, что возвращаемый объект сам является вызы­вающим объектом, и ни в коем случае не означает, что механизм возврата передает копию.

 

 

Задание

Напишите пояснение к данной функции:

 

const Stock & Stock::topval(const Stock & s) const

{

if (s.total_val > total_val)

return s; //объект в качестве аргумента else

return *this; //вызывающий объект

}

 


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: