Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Статические компоненты классов



 

Для изучения особенностей объявления компонент класса в языке С++ рассмотрим еще один класс, назовем его «клиент банка». В этом классе опишем основные характеристики, важные с точки зрения функционирования некоторой информационной системы по учету клиентов банка, а также основные операции, которые выполняются над данными о клиенте.

 

//Листинг 12. Класс «клиент банка»

class client

{ char *name; //ФИО клиента

char numb[10]; //номер счета клиента

float value; //сумма на счету

float percent; //величина процентной ставки для клиента

public:

client(char* s=" Без имени", char *n=" N0000", float x=0) //конструктор

{ int k=strlen(s); name=new char[k+1]; strcpy(name, s); strcpy(numb, n); value=x;

percent=0.1;

}

void PrintClient() //функция вывода информации о клиенте на экран

{ cout< < " \nВывод инф-ии о клиенте\n" < <

name< < '\t'< < numb< < '\t'< < value;

}

void ReadClient() //функция ввода информации о клиенте с клавиатуры

{ cout< < " \nВвод инф-ии о клиенте\n";

cin> > name> > numb> > value;

}

void ChangePercent(float p) //функция изменения процентной ставки

{ percent=p; }

void Add(float dx) //функция изменения суммы на счету

{ if (value+dx> 0)

value+=dx;

else

cout< < ”Нельзя снять такую сумму со счета”;

}

void AddPercent() //функция вывода начисления процентов на вклад

{ value*=percent+1; }

~client() { delete [] name; } //деструктор

};

main()

{client c(“Иванов И.И.”, ”N12345”, 1000); //определяем объект класса client c.PrintClient();

//выводим информацию л клиенте на экран c.Add(2000);

//добавляем на счет клиента 2000

c.PrintClient();

c.ChangePercent(0.05); //изменяем процентную ставку c.AddPercent();

//начисляем проценты на сумму вклада c.PrintClient();

}

В последнем примере для класса «клиент банка» определены ряд наиболее существенных характеристик, которые объявлены частными компонентными данными, а также несколько общедоступных методов, позволяющих обрабатывать эти характеристики. Если не принимать в расчет иллюстративный характер приведенного примера, а, следовательно, и недостаточное количество компонентных данных и методов в классе для его практического использования, у класса client есть еще один недостаток, который делает эту программную модель не вполне соответствующей реальному субъекту – клиенту банка. Если обратить внимание на компонент percent, то можно отметить, что процентная ставка в реальности вводится не для каждого клиента по отдельности, а является характеристикой банка и для всех клиентов конкретного банка является одинаковой. В связи с этим необходимо определить компонент percent таким образом, чтобы он хранился в памяти в единственном экземпляре при любом количестве объявленных объектов класса client, а его значение было бы общим для всех объектов. Этого можно добиться, объявив данный компонент статическим. Для этого в теле класса необходимо определить компонент следующим образом:

static тип имя_статического_компонентного_данного;

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

Тип имя_класса :: имя_статического_компонентного_данного=выражение;

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

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

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

Так как память под статический элемент данных выделяется еще до определения объектов, существует еще один способ обращения к нему:

имя_класса :: имя_статического_компонентного_данного

Такой способ используется для изменения значения статического члена данных в тот момент, когда недоступен ни один из объектов класса.

Необходимо также отметить, что на статические компоненты класса действуют ограничения по области видимости, задаваемые ключевыми словами public, protected и private в теле класса.

Объявим компонент percent класса client статическим.

 

//Листинг 13. Использование статических компонент в класса

class client

{ …

public:

static float percent;

};

float client:: percent=0.1;

main()

{client:: percent=0.2; //работать со статическими компонентными данными можно еще до

//определения объектов класса…

client c(“Иванов”, ”N12345”, 200);

c.percent=0.05; //…а можно и через имя уже определенного объекта

}

 

Статическими могут быть объявлены не только компонентные данные, но и

методы класса. Очевидно, что объявление метода класса статическим носит иное назначение, нежели чем компонентного члена данных, поскольку методы класса, как уже говорилось, и так существуют в памяти в единственном экземпляре. Статические методы класса обычно выступают в качестве интерфейса для работы с частными или защищенными статическими компонентными данными. Если, например, объявить компонент percent в классе client частным, то изменять его значение можно будет только с использованием метода ChangePercent. Однако вызвать метод ChangePercent можно только для конкретного объекта класса, тогда как изменять статические компонентные данные можно и без наличия созданных объектов. Статические методы класса позволяют работать со статическими компонентными данными без использования объектов данного класса. Объявляются такие методы в теле класса через ключевое слово static:

static тип имя_статического_метода( список_формальных_параметров );

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

имя_класса :: имя_статического_метода (список_фактических_параметров)

Рассмотрим пример с классом «клиент банка».

 

//Листинг 14. Использование статических компонент в класса

class client

{ …

static float percent;

public:

static void ChangePercent(float p)

{percent=p;

}

};

float client:: percent=0.1;

main()

{ //client:: percent=0.2; Такое обращение запрещено, т.к. percent- частный компонент

client:: ChangePercent(0.1);

client c(“Иванов”, ”N12345”, 200);

c.ChangePercent=0.05;

}

 

Дружественные функции

 

Для разделения интерфейса класса и его внутренней реализации различным компонентам класса присваивается разная область видимости с использованием ключевых слов public, protected и private. Компоненты, объявленные в секции private являются частными, то есть недоступными из окружения объекта, и работать с такими компонентами могут только компонентные функции класса. Однако, зачастую возникает необходимость обращаться к частным компонентам объекта из функций, не являющихся методами класса. Это, конечно, происходит не от желания программиста нарушить принцип инкапсуляции и обеспечить доступ извне к внутренней реализации класса. Просто в некоторых случаях необходимо организовать взаимодействие нескольких объектов разных классов, и функция, обеспечивающая взаимодействие, должна иметь доступ к частным компонентам одновременно нескольких объектов. Объявить функцию методом одновременно нескольких классов невозможно, поэтому в стандарте языка С++ предусмотрена возможность объявлять внешнюю по отношению к классу функцию дружественной данному классу. Для этого необходимо в теле класса описать некоторую внешнюю по отношению к классу функцию с использованием ключевого слова friend.

friend имя_функции ( список_формальных_параметров);

Функция - не член класса, - имеющая доступ к его закрытой части, называется другом этого класса.[Страуструп] Дружественная функция имеет доступ ко всем компонентам класса вне зависимости от их области видимости. Дружественная функция класса может быть обычной внешней функцией программы, а может – компонентной функцией другого класса.

Дружественная функция становится расширением интерфейса класса, и этот интерфейс реализует взаимодействие объекта с другими объектами программы. Рассмотрим простой пример.

 

//Листинг 15. Дружественные функции классов

class ClassB;

class ClassA

{ int x;

friend void func(ClassA, ClassB); //объявляем функцию дружественной классу ClassA

};

class ClassB

{ int y;

friend void func(ClassA, ClassB); //объявляем функцию дружественной классу ClassВ

};

void func(ClassA a, ClassB b)

{

cout < < a.x+b.y; //дружественная функция имеет доступ к частным компонентам обоих

// классов

}

main()

{

ClassA a; ClassB b; func(a, b);

}

 

В последнем примере определены два класса ClassA и ClassB, а также внешняя функция func, объявленная дружественной в обоих классах, благодаря чему func имеет доступ к частным компонентам x и y классов. При этом функция func является внешней по отношению к классу функцией и объекты класса должны либо передаваться ей в качестве параметров, либо объявляться в теле функции. Неявной передачи адреса объекта в дружественную функцию при вызове, как это осуществляется для компонентных функций класса, не происходит.

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

 

//Листинг 16. Дружественные функции из других классов.

#include < iostream.h>

#include < conio.h>

#include < string.h>

class bank;

class client

{ char * name; char numb[10]; float value;

char BankName[20]; //название банка, в котором хранится вклад

static float percent;

public:

client(char*, char *, float);

void PrintClient() { cout< < " \nВывод инф-ии о клиенте\n" < <

name< < '\t'< < numb< < '\t'< < value; }

void ReadClient() { cout< < " \nВвод инф-ии о клиенте\n";

cin> > name> > numb> > value; } static void ChangePercent(float p) { percent=p; } void Add(float dx) { value+=dx; }

void AddPercent() { value*=percent+1; }

~client() { delete [] name; }

void SetBank(bank& ); //функция записи клиента в список клиентов банка

};

float client:: percent=0.1;

client:: client(char* s=" Без имени", char *n=" N0000", float x=0)

{ int k=strlen(s); name=new char[k+1]; strcpy(name, s); strcpy(numb, n); value=x;

}

//класс «банк»

class bank

{ int count; //количество клиентов банка

char Name[20]; //название банка

client *spisok[10]; //массив клиентов банка

public:

bank(char *bankName){strcpy(Name, bankName); count=0; } //конструктор

friend void client:: SetBank(bank & ); //дружественная функция из другого класса

void PrintAll(); //функция вывода на экран информации о клиентах банка

~bank(); //деструктор

};

bank:: ~bank()

{ if(count)

for(int i=0; i< count; i++)

delete spisok[i];

}

void client:: SetBank(bank& b)

{ b.spisok[b.count]=this; //обращение к частной компоненте spisok класса bank b.count++;

//обращение к частной компоненте count класса bank strcpy(BankName, b.Name); //обращение к частной компоненте Name класса bank

}

void bank:: PrintAll()

{ for (int i=0; i< count; i++) spisok[i]-> PrintClient(); cout< < '\n';

}

main()

{

bank SB(" Сбербанк" ); //создаем объект класса bank int n;

do{

cout< < " Введите количество клиентов";

cin> > n;

}while(n> 10||n< 1)

client *c;

for(int i=0; i< n; i++)

{

c=new client; //создаем новый объект «клиент»

c-> ReadClient(); //вводим информацию о клиенте

c-> SetBank(SB); //записываем клиента в список банка

}

SB.PrintAll(); //выводим на экран информацию обо всех клиентах банка

}

 

В последнем примере определен новый класс bank, который содержит такие компоненты как количество клиентов банка, название банка, список клиентов банка. При этом классу client добавлено новое компонентное данное - название банка, в котором хранится его вклад. Взаимодействие между клиентом и банком устанавливается в функции SetBank, в которой адрес клиента заносится в массив клиентов банка spisok, увеличивается количество клиентов банка в компоненте count, а также для клиента заполняется компонент BankName – название банка, в котором хранится вклад. Таким образом, ком- понентная функция класса client должна иметь доступ к частным компонентам другого класса (класса bank). Для того, чтобы это стало возможным, функция SetBank объявляется как дружественная классу bank:

friend void client :: SetBank (bank & );

В общем виде объявление выглядит следующим образом:

friend тип имя_класса_функции :: имя_функции ( список_форм_параметров );

В функции SetBank для записи адреса объекта типа client в список клиентов банка используется константа this. Константный указатель this может использоваться только в нестатических компонентных функциях класса, причем использовать его необходимо без предварительного определения – он определяется транслятором автоматически. Указатель this хранит адрес объекта, для которого произведен вызов метода класса. Поддержка указателя this осуществляется транслятором путем переопределения компонентных функций класса и их вызовов в программе. На первом этапе преобразования каждая нестатическая функция-член преобразуется в функцию с уникальным именем и дополнительным параметром - константным указателем на объект класса. Затем преобразуются обращения к нестатическим данным-членам в операторах функции-члена. Они переопределяются с учётом нового параметра. В C++ при подобном преобразовании для обозначения дополнительного параметра- указателя (константного указателя) и постфиксного выражения с операциями обращения для обращения к нестатическим данным-членам используется одно и то же имя this. Вот как могла бы выглядеть функция-член SetBank после её переопределения:

 

void client:: client_SetBankl(client const *this, bank& b)

{ b.spisok[b.count]=this;

b.count++;

strcpy(this-> BankName, b.Name);

}

 

На втором этапе преобразуются вызовы функций-членов. К списку значений параметров выражения вызова добавляется выражение, значением которого является адрес данного объекта. Это вполне корректное преобразование. Дело в том, что нестатические функции-члены всегда вызываются для конкретного объекта. И потому не составляет особого труда определить адрес объекта. Например, вызов функции-члена SetBank для объекта c, который имеет вид c.SetBank(SB); после преобразования принимает вид: client_SetBank(& c, SB);

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

Причина изменения имени для функций-членов класса очевидна. В разных классах могут быть объявлены одноименные функции-члены. В этих условиях обращение к функции-члену класса непосредственно по имени может вызвать конфликт имён: в одной области действия имени одним и тем же именем будут обозначаться различные объекты - одноименные функции-члены разных классов. Стандартное преобразование имён позволяет решить эту проблему.

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

В языке С++ для класса кроме дружественной функции можно объявить дружественной класс. Все компонентные функции дружественного класса имеют доступ к частным и защищенным компонентам того класса, в котором он объявлен другом. Для того чтобы предоставить некоторому классу (назовем его класс1) свойства друга другого класса (класс2) необходимо в теле класса2 поместить следующую строку:

friend class имя_класса1;

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

 

//Листинг 17. Дружественный класс

#include < iostream.h>

#include < conio.h>

#include < string.h>

class bank;

class client

{ friend class bank; //объявляем класс bank дружественным классу client client *next; //адрес следующего клиента в списке клиентов банка char * name;

char numb[10];

float value;

static float percent;

client(char*, char *, float);

void PrintClient() { cout< < " \nВывод инф-ии о клиенте\n" < <

name< < '\t'< < numb< < '\t'< < value; }

void ReadClient() { cout< < " \nВвод инф-ии о клиенте\n";

cin> > name> > numb> > value; } static void ChangePercent(float p) { percent=p; } void Add(float dx) { value+=dx; }

void AddPercent() { value*=percent+1; }

~client() { delete [] name; }

};

float client:: percent=0.5;

client:: client(char* s=" Без имени", char *n=" N0000", float x=0)

{ int k=strlen(s); name=new char[k+1]; strcpy(name, s); strcpy(numb, n); value=x;

}

class bank

{ int count;

char Name[20];

client *first; //адрес первого клиента в списке клиентов(клиенты записываются в

//динамический список)

client *head; //адрес последнего клиента в списке клиентов

public:

bank(char *bankName)

{strcpy(Name, bankName); count=0; first=head=NULL; }

void AddClient();

void PrintAll();

~bank();

};

bank:: ~bank() //деструктор уничтожает список клиентов банка

{ if(count)

{ client *c=first;

while(c)

{ c=first-> next; delete first; first=c;

} } }

void bank:: AddClient() //функция добавления нового клиента в список клиентов

{ if (! count)

{first=new client; head=first; head-> next=NULL; head-> ReadClient();

count=1;

}

else

{ head-> next=new client;

head=head-> next; head-> ReadClient(); head-> next=NULL; count++; }}

void bank:: PrintAll() //функция вывода информации обо всех клиентах на экран

{ client *c; c=first; while(c)

{c-> PrintClient();

c=c-> next;

} }

main()

{ //client cl; Ошибка! Все компоненты client частные

bank SB(" Сбербанк" );

char c=0;

while(c! =27) //цикл до нажатия клавиши ESC

{ SB.AddClient(); //ввод информации об очередном клиенте

c=getch();

} SB.PrintAll();

}

В программе вновь определены два класса: bank и client. Класс client хранит информацию о клиенте банка, а также необходимые интерфейсные методы. Класс банк хранит список всех клиентов, хранящих свои вклады в данном банке. Список клиентов оформлен в виде динамического односвязного списка, что позволяет не ограничивать максимально допустимое количество клиентов банка. В связи с этим в классе client появляется новый компонент – next, хранящий адрес следующего клиента в списке, а в классе bank – компонентные данные first и head, хранящие адрес первого и последнего клиента в списке. Соответственно, функции класса bank создают, просматривают, уничтожают динамический односвязный список объектов класса клиент. При этом класс bank должен быть обязательно дружественен классу client, поскольку методы AddClient, PrintAll и деструктор класса bank работают с частными компонентами класса client (в частности, с компонентами next, ReadClent, PrintClient, конструктором и деструктором). Необходимо обратить внимание на то, что в последнем примере все компоненты класса client (и компонентные данные, и методы класса, и даже конструктор с деструктором) являются частными. Таким образом, в любой внешней по отношению к классу функции (например, в функции main) запрещен доступ к компонентам класса client, более того, запрещено даже создание объекта данного класса в main, поскольку определение объекта сопровождается вызовом конструктора, а он в данном примере также объявлен частным. В такой ситуации единственным способом работы с объектами класса client является использование дружественных функций или дружественных классов.

 

Перегрузка операций

 

Классы вводят в программу новые пользовательские типы данных. Такие типы могут использоваться наравне со стандартными (базовыми): они могут использоваться для определения новых переменных, могут входить в списки параметров функций и определять тип возвращаемого значения. В условиях фактического равноправия производных и основных типов данных должна существовать возможность сохранения привычной структуры выражений при работе с данными производных типов. Это означает, что выражение для вычисления суммы двух слагаемых уже известного нам типа array по своей структуре не должно отличаться от соответствующих выражений для слагаемых типа int или float. Но большинство операций языка C++ определены лишь для основных типов данных. Использование в качестве операндов операций выражений производных типов вызывает ошибки трансляции.

 

int a, b, c;

c=a+b; // использование операндов базовых типов для операции сложения разрешено

array m1(4), m2(4), m3(4);

// m1=m2+m3; ошибка!!! использование операндов производных типов для

//операции сложения запрещено

 

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

Функция, перегружающая операцию в С++ называется «операция- функция» и должна выглядеть следующим образом:

тип operator знак_операции (список формальных_параметров)

{тело_функции

}

 

Здесь тип – тип возвращаемого функцией значения, operator - ключевое слово, определяющее, что данная функция перегружает операцию, знак_операции – знак той операции языка С++, которую перегружает данная функция. Количество параметров функции определяется количеством операндов у соответствующей операции, а также способом определения функции. Операция-функция может быть как компонентной функцией некоторого класса, так и внешней функцией. Рассмотрим пример перегрузки операций для класса array2 (двумерный массив целых чисел).

 

//Листинг 18. Перегрузка операций для класса «двумерный массив целых чисел»

#include < iostream.h>

#include < conio.h>

class array2

{ int **mas; //указатель на массив

int n, m; //количество строк и столбцов

public:

array2(int, int); //конструктор

void ReadMas(); //ввод массива с клавиатуры

void WriteMas(); //вывод элементов массива на экран

~array2(); //деструктор

operator int(); //перегрузка операции приведения типа

friend array2& operator*(array2&, array2& ); //дружественная функция перегрузки

//операции умножения

void operator=(array2& ); //перегрузка операции присвоения

};

array2:: array2(int a, int b){n=a; m=b; //динамически выделяем память под двумерный массив

mas=new int *[n]; for (int i=0; i< n; i++) mas[i]=new int[m];

}

void array2:: ReadMas(){

cout< < " Введите массив \n";

for (int i=0; i< n; i++) for (int j=0; j< m; j++) cin> > mas[i][j]; }

void array2:: WriteMas() {

for (int i=0; i< n; i++)

{ for (int j=0; j< m; j++) cout< < mas[i][j]< < '\t'; cout< < '\n';

} }

array2:: ~array2(){for (int i=0; i< n; i++) delete [] mas[i]; delete[]mas;

}

array2& operator*(array2& m1, array2& m2) //внешняя функция перегрузки операции

//умножения

{ if(m1.m==m2.n)

{array2 *pta;

int s;

pta=new array2(m1.n, m2.m);

for(int i=0; i< m1.n; i++)

{ for(int j=0; j< m2.m; j++)

{s=0;

for(int k=0; k< m1.m; k++) s+=m1.mas[i][k]*m2.mas[k][j]; pta-> mas[i][j]=s;

}

}

return *pta;

}

else cout< < " Error";

}

array2:: operator int()

{ int sum=0;

for(int i=0; i< n; i++) for(int j=0; j< m; j++) sum+=mas[i][j]; return sum;

}

void array2:: operator=(array2& m2)

{ if(n==m2.n& & m==m2.m)

for(int i=0; i< n; i++) for(int j=0; j< m; j++) mas[i][j]=m2.mas[i][j]; else cout< < " Error";

}

main()

{ array2 m(2, 3), m1(3, 4), m2(2, 4);

m.ReadMas();

m1.ReadMas();

m2=m*m1; //перемножаем массивы по правилу перемножения матриц

m2.WriteMas();

int c=int(m2); //получаем сумму элементов массива

cout< < c;

getch();

}

 

В приведенном примере для класса «двумерный массив целых чисел» перегружены три операции: операция умножения ‘*’, выполняющая умножение массива по правилам перемножения матриц, операция приведения типа ‘int()’, которая применительно к массиву вычисляет сумму элементов массива, а также операция присвоения ‘=’, которая поэлементно копирует содержимое одного массива в другой. Рассмотрим подробнее операцию-функцию operator *. Данная операция-функция определена как внешняя по отношению к классу функция с правами друга, так как она работает с частными компонентами класса n, m, mas. Функция имеет два параметра – это операнды операции умножения. После такого объявления функции любое использование в программе выражения типа a*b при условии, что а и b являются объектами класса array2, приводит к вызову operator *(a, b). Подобный вызов операции-функции можно непосредственно поместить в текст программы, но он уступает в понятности и наглядности использованию обычной операции умножения. Таким образом, при определении операции-функции как внешней функции количество ее параметров должно совпадать с арностью перегружаемой операции, поскольку операнды перегруженной операции становятся фактическими параметрами соответствующей операции-функции.

Для перегрузки операции приведения типа ‘int()’ определена операция-функция как метод класса array2. При подобном определении один из операндов операции становится тем объектом, для которого вызывается операция- функция, а остальные операнды (если они есть) передаются как фактические параметры. Таким образом, для вызова операции приведения типа с параметром – объектом класса array2 в последнем примере: int(m2) будет вызвана операция-функция в следующем варианте: m2.operator int()

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

 

//Листинг 19. Определение операции-функции как метода класса

class array2

{ …

array2& operator*(array2& m2) //функция перегрузки операции

//умножения как метод класса

{ if(m==m2.n)

{array2 *pta;

int s;

pta=new array2(n, m2.m);

for(int i=0; i< n; i++)

{ for(int j=0; j< m2.m; j++)

{s=0;

for(int k=0; k< m; k++) s+=mas[i][k]*m2.mas[k][j]; pta-> mas[i][j]=s;

}

}

return *pta;

}

else cout< < " Error

}

};

main()

{ array2 m(2, 3), m1(3, 4), m2(2, 4);

m2=m*m1; //можно записать в виде m2=m.operator *(m1)

}

 

Перегрузка операции присваивания необходима для класса array2 в связи с тем, что обычное копирование компонентных данных из одного объекта в другой, которое производит операция присваивания по умолчанию, не подходит для поставленной задачи. Если написать выражение m1=m2, не переопределяя операцию присваивания, то компонент mas одного объекта будет скопирован в компонент mas другого, что приведет к использованию обоими объектами одного и того же динамического массива в дальнейшем. Переопределив же операцию присваивания, мы при присваивании объектов копируем элементы одного динамического массива в другой.

При перегрузке операций существует ряд ограничений: нельзя перегружать некоторые операции (‘.’, ’?: ’, ’:: ’, ‘sizeof’, ‘##’, ‘#’, ‘.*’), нельзя вводить новые знаки операций, нельзя изменять приоритеты операций, для некоторых операций (‘=’, ’[]’, ’-> ’) операцию-функцию можно определять только как нестатическую компонентную функцию класса.

 

Наследование классов

 


Поделиться:



Популярное:

  1. Активные компоненты эфирных масел, синергизм.
  2. Билет №4.Классы и объекты, Члены классов. Статические члены классов.
  3. Вегетативные и эмоциональные компоненты боли
  4. Влияние ионизирующего облучения (радиации) на компоненты пищи
  5. Выбор температурных классов электрооборудования
  6. Данные члены и управление доступом к элементам классов.
  7. Диаграмма плавкости системы, компоненты которой
  8. Идентификация социальных классов
  9. Инновационные компоненты педагогической системы освоения ценностей физической культуры и спорта
  10. Интегрирование рациональных дробей. Интегрирование некоторых классов иррациональных и трансцендентных функций.
  11. Использование указателей на базовые классы при адресации объектов произвольных классов.
  12. Исследования влияния параметров пассивных элементов на статические и динамические характеристики базового логического элемента


Последнее изменение этой страницы: 2016-07-14; Просмотров: 663; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.158 с.)
Главная | Случайная страница | Обратная связь