Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Sb97809

.pdf
Скачиваний:
2
Добавлен:
13.02.2021
Размер:
441.54 Кб
Скачать

7. ПЕРЕДАЧА ОБЪЕКТОВ КАК АРГУМЕНТОВ ФУНКЦИИ

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

Пример:

#include <iostream.h> class OBY {int i; public:

void set_i (int x) {i=x;}

void out_i (void) {cout <<i ;} }; void f (OBY x);

main (void)

{

OBY A; A.set_i (10); f (A); A.out_i ();

}

void f (OBY x)

{

x.out_i(); x.set_i(100); x.out_i();

}

Можно передать параметр объекта по ссылке, иными словами передать адрес объекта, в таком случае все изменения в функции изменят сам объект.

При передаче объекта в качестве параметра по значению создается локальная копия объекта. Может быть вызван конструктор и деструктор, динамически выделена память.

8. МАССИВЫ ОБЪЕКТОВ

Массивы объектов создаются так же, как массивы элементов, поэтому можно создавать многомерные массивы объектов.

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

11

data md [10];

data day (30, 3, 2007); md [0]. set (1, 1, 2000); ….

md [9]. set (1, 1, 2007);

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

#include<stdio.h>

void sort(int arr[],int (n); main()

{int mass[10]; size=10,i;

printf(“введите переменные массива\n”); for (i=0; i<size; i++) scanf(“%d”,&mass[i]);

printf(“до сортировки\n”); for (i=0; i<size; i++) printf(“%5d”,mass[i]); printf(“\n”); sort(mass,size);

printf(“после сортировки|n”);

for (i=0; i<size; i++)printf(“%d”,mass[i]);

}

void sort(int arr[ ],int n) {int i,j,tmp;

for (i=0; i<n; i++) for (j=0; j<n-i-1; j++) if (arr[j+1]<arr[j]) {tmp arr[j]; arr[j]=arr[j+1]; arr[j+1]=tmp;

}

}

12

9. УКАЗАТЕЛЬ НА ОБЪЕКТ

Как и на другие типы данных, ссылаться на объект можно через указатель, при этом доступ к элементам объекта осуществляется при помощи операции “→”, аналогично операторам Структура и Объединение.

Пример:

class example {…}; main (void)

{

example ob,*p; ob.set_num (1); p=&ob; p→set_num (2);

}

10. КЛЮЧЕВОЕ СЛОВО THIS

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

Функции-члены класса имеют доступ к private-данным. Обращаться к ним можно по имени, а можно по ссылке.

Пример:

# include <iostream.h> class cl {

int i;

public: void load i (int val) {i=val;} ≡ {this -> i=val; }

int get_i(void) {return this -> I;}}; main (void)

{cl c; c.load_i(100); cout <<c.get_i();

}

Таким образом указатель на объект, для которого вызвана функциячлен, является скрытым параметром функции. Главным образом this используется при написании функций-членов, которые манипулируют непосредственно указателями.

13

11. ПЕРЕГРУЗКА ФУНКЦИЙ И ОПЕРАЦИЙ

Полиморфизм – это свойство, позволяющее использовать одно имя для обозначения действий, общих для родственных классов. При этом конкретизация выполняемых действий осуществляется в зависимости от типа обрабатываемых данных.

Формы полиморфизма в C++:

перегрузка функций и операций;

виртуальные функции;

обобщенные функции (шаблоны).

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

11.1. Перегруженные функции

Перегрузка позволяет задействовать одно имя для нескольких функций. Две или более функций могут иметь одно и то же имя и отличаться количеством или типом параметров. Обычно перегруженные функции используются для реализации похожих действий над данными разного типа.

В С есть стандартные функции преобразования строки в число типа int, float, long (atoi, atof, atoll). В С++ есть аналог этих функций – перегруженная функция atonum для всех типов числовых данных.

Пример:

#include <iostream.h> int sqr_it (int i);

float sqr_it (float d); long sqr_it (long l); main ()

{

int i=7; float d=1,5; long l=36000; cout<<sqrt_it (i); cout<<sqrt_it (d); cout<<sqrt_it (l); unsigned int u=4; cout<<sqrt_it (u);

14

}

int sqrt_it (int i) { return i*i; }

float sqrt_it (float d)

{return d*d; } long sqrt_it (long l)

{return l*l; }

Перегруженные функции не могут отличаться только типом возвращаемого значения.

int sqrt_it (long i); long sqrt_it (long i); sqrt_it (67000);

При обращении перед компилятором встает неразрешимая проблема: какую из перегруженных функций выбрать?

11.2. Перегрузка конструктора

Перегрузка конструктора класса осуществляется просто объявлением конструкторов с различным набором параметров.

Пример: class date{

int month, day, year; public: date (int, int, int); date (char *);

date (int); date (void);

};

date begin; date today (23);

date my_day (05,06,2000); date xmas (“02 января”);

В зависимости от того, какие параметры заданы, выбирается соответствующий конструктор.

15

11.3. Выбор экземпляра функции

При выборе требуемого экземпляра функции осуществляется сравнение типов и числа параметров и аргументов:

параметры – формальные параметры функции;

аргументы – реальные значения при вызове функций. Существует три возможных варианта:

1. Точное соответствие типов аргументов параметрам одного из экзем-

пляров функции.

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

3.Соответствие может быть достигнуто более чем для одного экземпляра функции. При этом необходимо иметь ввиду, что преобразование типов, определенное пользователем, имеет меньший приоритет по сравнению со стандартным преобразованием. Если соответствие типов достигается путем равноправных преобразований, компилятор выдает сообщение об ошибке: «невозможно определить однозначно экземпляр функции».

void f1(char);

f1(‘b’);

void f1(unsigned int);

f1(723);

void f1(char*);

f1(“Привет”);

Здесь наблюдается точное соответствие аргументов параметрам для одного из экземпляров функций.

Преобразование типов: char, short, const ≡ int float ≡ double

void f2(long); void f2(char *);

f2(10); int > long

Осуществляетсястандартноепреобразованиетиповаргументоввпараметр. Замечание: аргумент любого числового типа можно преобразовать стандартнымпутемклюбомучисловомутипу, любойуказатель– куказателюнаvoid.

void f3(long); void f3(int); void f3(double);

Преобразования типов равноправны – компилятор выдаст ошибку.

16

11.4. Перегрузка стандартных операций

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

Примером такой перегрузки может являться операция сложения.

C++ позволяет расширить область применимости этой операции, например, для сложения векторов в трехмерном пространстве. Для этого нужно определить новое поведение стандартной операции «+» применительно к новым типам данных. Это допускается, если хотя бы один из операндов операции является объектом определенного пользователем класса.

Не могут быть переопределены или перегружены:

1)операция условия «?»;

2)уточнение области видимости «::»;

3)sizeof.

Переопределение операции выполняется с помощью определения операторной функции следующего формата:

Тип_результат operator # (список аргументов) {операторы тела функции;}

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

Тип_результат класс ::operator # (список параметров) {…};

Пример: реализовать перегрузку операций сложения и присваивания относительно класса vector.

# include <iostream.h> class vector {int x,y,z;

public: vector operator+(vector t); vector operator = (vector t); void show(void);

void assign (int mx, int my, int mz);}; vector vector :: operator + (vector t)

{vector temp; temp.x=x+t.x; temp.y=x+t.y; temp.z=x+t.z;

17

return temp;}

vector vector :: operator=(vector t) {x=t.x;

y=t.y;

z=t.z;

return *this;}

void vector :: show(void) {cout <<x<<y<<z;}

void vector :: assigned (int mx, int my, int mz) {x=mx;

y=my;

x=mz;} main (void)

{vector a,b,c; a.assign(1,2,3); b.assign(10,10,10); c=a+b; c=a+b+c; c=b=a;

b.show();

c.show();

c.show();

c.show(); b.show(); }

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

Возвращаемое значение имеет тип vector. Это позволяет использовать

выражения типа:

 

 

а + b + c

либо

c = b = a.

Операция сложения не изменяет своих операндов; операция присваивания модифицирует операнд, стоящий слева.

Подобным образом можно перегрузить ++ и – –: vector operator ++ (void)

18

vector vector :: operator ++ (void) {x++;

y++;

z++;

return *this;}

Чтобы отличить префиксную операцию от постфиксной, в постфиксной операции при описании функции добавляют фиктивный целочисленный указатель:

vector vector :: operator++(int) {vector tmp;

tmp=*this;

x++;

y++;

z++; return tmp;}

Значение координат увеличивается, но возвращается старое значение объектов.

11.5. Дружественные функции-операции

Отличие состоит в том, что нельзя использовать скрытый указатель this. Для бинарных операций должны передаваться два аргумента, для унар-

ных – один аргумент.

# include <iostream.h> class vector (int x,y,z;

public: friend vector operator+(vector t); vector operator = (vector t);

void show(void);

void assign(int mx, int my, int mz);}; vector operator+(vector t1, vector t2) {vector tmp;

temp.x=t1.x+t2.x;

temp.y=t1.x+t2.y;

temp.z=t1.x+t2.z; return temp;}

Перегрузку операции умножения объекта типа vector на целое можно записать и функцией-членом, и дружественной функцией. Операцию умножения целого на vector можно определить только через дружественную функцию.

19

11.6. Использование ссылочных переменных

Перегрузка унарных операций. Декремент дружественной функции требует использования ссылки.

Friend vector operator ++ (vector &opl) {opl.x++;

opl. y++; opl.z++; return opl;}

Перегрузка операции индексации []. Индексация – бинарная операция,

где первый операнд – объект класса, второй – целочисленный индекс. Перегрузка операции индексации позволяет работать с элементами объекта vector, как с элементами массива.

#include <iostream.h> class vector {int v[3];

public: vector(int a=0; int b=0; int c=0) {v[0]=a;

v[1]=b;

v[2]=c;}

vector operator +(vector t); vector operator =(vector t); int & operator[](int i); void show(void);};

vector vector::operator+(vector t) {vector tmp;

for (int i=0; i<3; i++) tmp.v[i]=t.v[i]+v[i] return tmp;}

vector vector::operator=(vector t) {vector tmp;

for (int i=0;i<3;i++) v[i]=t.v[i];

return *this;}

int &vector::operator[](int i) {return v[i];}

void vector::show(void) {for (int i=0;i<3;i++)

20

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]