Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Язык программирования Сpp 25.09.11 (2).doc
Скачиваний:
16
Добавлен:
19.08.2019
Размер:
10.09 Mб
Скачать

7.3. Создание объектов и обращение к членам объекта

В рассмотренных примерах мы уже создавали объекты классов и знаем, что после того как класс созан можно объявить один или несколько его объектов, т.е. экземпляров (переменных) данного класса. Процесс объявления ничем не отличается от объявления переменных базового типа, например если создан класс с именем MyClass, то объявление выглядит так:

MyClass object1, object2(x1), object3(x1,x2,x3);

Иначе говоря объявление объекта выглядиттак

Имя_класса имя_объекта(список_членов класса);

Членами класса могут быть данные, функции, классы, имена типов. Хотя мы в своих примерах будем использовать только базовые типы.

Из рассмотренных примеров уже стало ясно, что к членам объекта можно обращаться с помощью оператора точка. Еще раз подробнее рассмотрим этот вопрос. Предположим, что имеется класс MyClass, с соответствующим ему конструктором MyClass(описание аргументов), функцией MyFunction(x,y) и данными u,v. Тогда после создания объекта, который в данном случае объявляется как

MyClass MyObject(значение аргументов);

к функции можно обратиться так

MyObject. MyFunction(x,y),

а к переменным

MyObject.u; MyObject.v ;

Ниже приведен пример, в котором конструктор класса записывает числа от 0 до 9 в массив из 10 элементов. Функция print выводит на экран этот массив несколько раз. Количество обращений к этой функции зависит от числа rule, которое вводится из главной функции main. При создании объекта MyObject массив заполняется целыми числами и выводится на экран. После этого формируется новый массив и происходит обращение к функции print через MyObject.print .

#include<iostream>

using namespace std;

// Пример класса с именем MyClass

class MyClass{

public:

int m; /*Вспомогательная переменная необходимая для иллюстрации

работы программы */

void print(int intArray[10]);

MyClass(int rule);

};

void MyClass::print(int intArray[10]){ // Описание функции члена

for(int i=0;i<10;i++) cout<<intArray[i]<<",";

cout<<endl;

cout<<"m="<<m<<endl;

} //Здесь точка с запятой не ставятся, т.к. это функция

MyClass::MyClass(int rule){ // Описание конструктора

int array[10];

m=1;

cout<<"rule="<<rule<<endl;

for(int i=0;i<10;i++) array[i]=i;

for(int i=0;i<rule;i++) print(array);

} /*Здесь точка с запятой не ставятся хотя их присутствие

не вызовет ошибки, т.к. это будет пустой оператор */

//-----------------------------------------------------

#include <windows>

void main(){

SetConsoleOutputCP(1251); //Смена кодировки

int number, arr[10]={9,8,7,6,5,4,3,2,1,0}; //Инициализация массива

cout<<"Введите целое число"<<endl;

cin>>number;

MyClass MyObject(number);

cout<<”Число m и массив изменены”;

MyObject.m=10; // Изменяется вспомогательная переменная

MyObject.print(arr); // Выводится новый массив

}

Результат можно видеть на рисунке

Этот пример говорит о том, что оператор точка позволяет выполнить обращение к членам класса.

При работе с объектами можно использовать указатели. Для этого, сначала, нужно объявить указатель.

MyClass object1, object2, *pointerMyClacc;

где *pointerMyClacc – указатель на объект класса MyClacc.

Затем присвоить указателю адрес того объекта с которым предполагается дальнейшая работа.

pointerMyClacc=& object1;

К членам класса можно обращаться через указатель с помощью оператора -> следующим образом:

Указатель_класса->имя_члена_класса

Например, если MyClass имеет поля

int i,j,k;

double x,y,z;

то следующий код будет верен.

pointerMyClacc->i=1; pointerMyClacc->j=2;

pointerMyClacc->k= pointerMyClacc->i- pointerMyClacc->j;

pointerMyClacc->x=1.234; pointerMyClacc->y=0.567e-5;

pointerMyClacc->z= pointerMyClacc->x+ pointerMyClacc->y;

С помощью оператора -> можно бращаться к функции класса. Так если в MyClacc есть функция sum(x,y), то ее можно вызвать так:

pointerMyClacc->sum(x,y);

Код всей программы приведен ниже

//Пример применения указателей

class MyClass{

public:

int i,j,k;

int sum(int,int);

double x,y,z;

};

int MyClass::sum(int a,int b){

return a+b; return a+b;

}

//-------------------------------------

#include <iostream.h>

void main(){

MyClass mCL,*pointerMyClacc;

pointerMyClacc=&mCL;

pointerMyClacc->i=1; pointerMyClacc->j=2;

pointerMyClacc->k= pointerMyClacc->i- pointerMyClacc->j;

pointerMyClacc->x=1.234; pointerMyClacc->y=0.567e-5;

pointerMyClacc->z= pointerMyClacc->x+ pointerMyClacc->y;

cout<<pointerMyClacc->k<<endl;

cout<<pointerMyClacc->z<<endl;

int x,y;

cout<<"x=";

cin>>x;

cout<<"y=";

cin>>y;

cout<<"RESULTAT="<<pointerMyClacc->sum(x,y)<<endl;

}

Внимательного читателя фраза – “указатель класса” должна смутить. Действительно, о каких указателях может идти речь, если память выделяется объектам при их инициализации, а не самим классам. Конечно, это указатели на компоненты объектов. В данном случае название не совсем удачно.

Итак, к члену класса можно обращаться либо так:

имя_объекта.имя_члена класса

либо так:

указатель_на_объект_класса -> имя_члена класса

Но есть еще один способ – создать указатель члена класса не создавая указателя на объект. Продемонстрируем эту возможность на примере. Пусть имеется класс с именем с именем MyClass в котором есть переменная m типа int. В этом случае можно объявить указатель на переменную m.Пусть имя этого указателя будет point_m, а его объявление выглядит так:

int (MyClass::*point_m); /*Объявляется как обычный указатель, только после типа все записывается в скобках и кроме того добавляется имя класса */

Далее идет присвоение адреса

point_m=&MyClass::m; //Присвоение адреса

Разыменовывание переменной и присвоение значения:

MyObject.*point_m=100;

Этот способ не очень поятен, но еще более непонятно, по крайней мере на первый взгляд, выглядят операции с указателями для функций. Указатели на функции, принадлежащие классу (напомним, что они еще называются методами), имеют синтаксис:

Тип_возвращаемого_значения (имя_класса::*имя_указателя_на_метод) (спецификация параметров функции);

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

void (MyClass::*pointPrint)(int intArray[10]); /*Это объявление

указателя с именем pointPrint для функции */

после чего следует задать его значение

pointPrint=&MyClass::print; //присваивание адреса или настройка

Наконец вызвать функцию по указателю

(MyObject.*pointPrint)(arrZero);

Подобным образом можно выполнить указатель на данные.

Рассмотрим пример программы иллюстрирующий сказанное. В программе используется класс, содержащий одну переменную m и функцию print(int intArray[10]), которая имеет параметр в виде массива.

// Пример MyClass с указателями

#include<iostream>

using namespace std;

class MyClass{

public:

int m;

void print(int intArray[10]);

MyClass(int rule);

};

//------------Определение функции и конструктора--------

//функция print выводит на экран массив intArray и целое число m

void MyClass::print(int intArray[10]){

for(int i=0;i<10;i++) cout<<intArray[i]<<",";

cout<<endl;

cout<<"m="<<m<<endl;

}

/* конструктор, создает массив целых чисел от 0 до 9 включительно

и выводит на экран весь массив и число m заданное в переменной

rule количество раз */

MyClass::MyClass(int rule){

int i,array[10];

m=1;

cout<<"rule="<<rule<<endl;

for(i=0;i<10;i++) array[i]=i;

for(i=0;i<rule;i++) print(array);

};

//---------------Описание фунции main()-------------

void main(){

int number=5;

MyClass MyObject(number);

int arrZero[10]={0,0,0,0,0,0,0,0,0,0}; //Вспомогательный массив

//----- иллюстрация обращения к членам класса через указатель---

int (MyClass::*point_m); /*Объявление указателя класса MyClass

для членов типа int */

point_m=&MyClass::m; /*присвоение адреса переменной m*/

MyObject.*point_m=100; /*разыменовывание переменной m

и присвоение ей значения 100 */

//Обращение к функции через указатель

void (MyClass::*pointPrint)(int intArray[10]); /*объявление

указателя на функцию из класса MyClass с параметром в виде

массива из 10-ти элементов, которая возвращает тип int */

pointPrint=&MyClass::print; //инициализация указателя

(MyObject.*pointPrint)(arrZero); //вызов функции

}

Результат выполнения программы представлен на рисунке. После объявления объекта, на экран 5 раз выводится созданный конструктором массив целых чисел от 0 до 9 и число m, определенное в конструкторе. Функция main() заканчивается присвоением через указатель нового значения числу m и вызове на экран метода print с новым массивом.

Следует заметить, что указатель на компоненты класса можно также использовать в качестве фактического параметра при вызове функций, т.е. вместо параметра передавать адрес.

Приведенные примеры используют операцию разыменовывания указателей на компоненты класса. Хотя к членам объектов можно обратиться с помощью операции “->*” . Синтаксис здесь такой

Указатель_на_объект_класса->*указатель_на_данные

Указатель_на_объект_класса->*указатель_на_метод(параметры)

В качестве иллюстрации возьмем предыдущий пример и заменим в нем имя объекта на указатель класса.

// Пример MyClass – класс с указателями

#include<iostream>

using namespace std;

class MyClass{

public:

int m;

void print(int intArray[10]);

MyClass(int rule);

};

//------------Определение функции и конструктора--------

//функция print выводит на экран массив intArray и целое число m

void MyClass::print(int intArray[10]){

for(int i=0;i<10;i++) cout<<intArray[i]<<",";

cout<<endl;

cout<<"m="<<m<<endl;

}

/* конструктор, создает массив целых чисел от 0 до 9 включительно

и выводит на экран весь массив и число m заданное в переменной

rule количество раз */

MyClass::MyClass(int rule){

int i,array[10];

m=1;

cout<<"rule="<<rule<<endl;

for(i=0;i<10;i++) array[i]=i;

for(i=0;i<rule;i++) print(array);

};

//---------------Описание фунции main()-------------

void main(){

int number=5;

MyClass MyObject(number),*pointMO; //объявление указателя класса

pointMO=&MyObject;

int arrZero[10]={0,0,0,0,0,0,0,0,0,0}; //Вспомогательный массив

//----- иллюстрация обращения к членам класса через указатель---

int (MyClass::*point_m);

для членов типа int */

point_m=&MyClass::m;

pointMO->*point_m=100; /*применение двух указателей для присвоения значения переменной класса */ и присвоение ей значения 100 */

//Обращение к функции через указатель класса и указатель функции

void (MyClass::*pointPrint)(int intArray[10]); /*объявление

указателя на функцию из класса MyClass с параметром в виде

массива из 10-ти элементов, которая возвращает тип int */

pointPrint=&MyClass::print;

(pointMO->*pointPrint)(arrZero); /*обращение к функции через два

указателя */

}

Результат этой программы точно такой как и предыдущей.

При работе с классами используется один необычный указатель c фиксированным именем this. Обычно он используется тогда, когда нужно разделить переменные класса и параметры функции с одинаковыми именами. Например:

#include<iostream>

using namespace std;

class summa{

int x,y; //переменные класса

public:

summa(int x, int y);

};

summa::summa(int x, int y){

this->x=1;this->y=2; //инициализация переменных класса

cout<<"thisx="<<this->x<<endl;

cout<<"thisy="<<this->y<<endl;

cout<<"this->x+this->y="<<this->x+this->y<<endl;

cout<<"x="<<x<<endl;

cout<<"y="<<y<<endl;

cout<<"x+y="<<x+y<<endl;

}

void main(){

int a=3,b=4;

summa sum(a,b);

}

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

object.fun1(); /* предполагается, что object

* это имя объекта*/

Функции fun1()автоматически передается указатель на объект object. Этот указатель и называется this. Указатель this автоматически передается только функциям-членам.

Рассмотрим предварительный пример в котором пока нет указателя this. В коде класса приведенного ниже используется функция strcpy (string copy) из библиотеки string. Функция strcpy

// Демонстрация указателя this

#include <iostream>

#include <string>

using namespace std;

class inventory { //класс называется опись

char item[20]; // item в переводе означает пункт, статья, позиция

double cost; // cost в переводе - цена

int on_hand;

public:

/*далее идет объявление конструктора, котоый в дальнейшем

не описан, т.к. все что он делает определено в его объявлении */

inventory(char *i, double c, int o) {

strcpy(item, i);

cost = c;

on_hand = o;

}

void show(); //функция, осуществляющая вывод

};

void inventory::show()

{

cout << item; //вывод на экрае всего массива

cout << ": $" << cost;

cout << " On hand: " << on_hand << "\n";

}

int main()

{

inventory object("wrench", 4.95, 4);

object.show();

return 0;

}