Продолжаем определение класса ComplexType. Теперь объявим и определим функцию-член PrintVal, которая будет выводить значение чисел-объектов.
Прототип функции разместим в классе: void PrintVal();
При определении функции используется квалифицированное имя:
void ComplexType::PrintVal() { cout << "(" << real << ", " << imag << "i)" << endl; cout << (int)CTcharVal << ", " << x << "…" << endl; }
Значения данных-членов объекта выводятся при выполнении выражения вызова функции PrintVal: CDw1.PrintVal();
Объекты класса имеют свои собственные экземпляры данных-членов. Данные-члены имеют свои собственные специфические значения. Вместе с тем, все объекты используют единый набор функций-членов, с помощью которого можно получить доступ к значениям данных-членов во всех объектах класса.
Среди операторов функции-члена PrintVal() нет ни одного оператора, который позволял бы определить, какому объекту принадлежат данные-члены. И, тем не менее, вызов этой функции для каждого из определённых и различным образом проинициализированных объектов, в том числе и для безымянного объекта, который создаётся в результате непосредственного вызова конструктора: ComplexType(0.0,0.0, 1).PrintVal(); ,
а также вызов функции для объекта, адресуемого указателем: pCD->PrintVal();
сопровождается сообщением о значениях собственных данных-членов. Заметим, что "собственные" данные-члены объектов, как и те функции-члены класса, с которыми мы уже успели познакомиться, считаются нестатическими данными и функциями-членами класса. Существуют также и статические члены класса, к изучению свойств которых мы обратимся в недалёком будущем.
Автоматическое определение принадлежности данных-членов конкретному объекту характерно для любой нестатической функции-члена класса. Объекты являются "хозяевами" нестатических данных и потому каждая нестатическая функция-член класса должна уметь распознавать "хозяйские" данные.
Вряд ли алгоритм распознавания хозяина данных очень сложен. Здесь проблема заключается совсем в другом: этот алгоритм должен быть реализован практически для каждой нестатической функции-члена класса. Он используется везде, где производится обращение к данным-членам объектов, а это означает, что на программиста может быть возложена дополнительная обязанность по кодированию. Несколько обязательных строк для каждой функции-члена? Да никогда…
К счастью, C++ освобождает программистов от утомительной и однообразной работы кодирования стандартного алгоритма распознавания. В C++ вообще многое делается без их участия. Функции-члены определяются как обычные функции. Транслятор переопределяет эти функции, обеспечивая при этом стандартными средствами связь между объектами и их данными. Эта связь реализуется благодаря специальному преобразованию исходного кода программы. Мы опишем это преобразование, условно разделив его на два этапа.
На первом этапе каждая нестатическая функция-член преобразуется в функцию с уникальным именем и дополнительным параметром - константным указателем на объект класса. Затем преобразуются обращения к нестатическим данным-членам в операторах функции-члена. Они переопределяются с учётом нового параметра. В C++ при подобном преобразовании для обозначения дополнительного параметра-указателя (константного указателя) и постфиксного выражения с операциями обращения для обращения к нестатическим данным-членам используется одно и то же имя this. Вот как могла бы выглядеть функция-член PrintVal после её переопределения: