Перегрузка операции приведения типа 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Перегрузка операции приведения типа



Операторные функции, осуществляющие преобразование объекта класса к другому типу, имеют формат: operator имя_нового_типа ();. Здесь, тип возвращаемого значения и параметры указывать не требуется. Для преобразований между основными типами и типами, определенными программистом используют два подхода: использование конструктора с одним аргументом при изменении основного типа на определённый пользователем и использование операции преобразования при изменении определённого пользователем типа на основной.

Преобразования объектов в основные типы и наоборот

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

Рассмотрим пример перевода английской меры длины в метры и обратно, в котором показано, как происходит преобразование основного типа в тип, определённый программистом, и наоборот.

const float Kmf = 3.280833; // êîýôôèöèåíò

class Dist {

private:

int feet;

float inch;

public:

Dist() { feet = 0; inch = 0.0; }

Dist(int f, float i) { feet = f; inch = i; }

Dist(float m) { //êîíñòðóêòîð ïåðåâîäà èç ìåòðîâ â ôóòû

float ff = Kmf*m;

feet = int(ff);

inch = 12*(ff-feet);

}

void show() {

cout << feet << "'-" << inch;

}

operator float() { //ìåòîä äëÿ ïåðåâîäà ÀÒÄ ê ñòàíäàðòíîìó float

float fut = inch/12; //d1.inch

fut = fut + float(feet); //d1.feet

return fut/Kmf;

}

};

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

int main() {

Dist d1;

float metr = 2.35, metr2=0.0;

d1 = Dist(metr); //переводим float в Dist

cout << "\nd1 = "; d1.show(); //увидим d1=7'-8.51949

metr2 = float(d1); //переводим Dist во float (можно написать просто metr2 = d1; )

cout << "\nmetr2 = " << metr2; //увидим metr2=2.35

getch(); return 0;

}

Для перехода от основного типа float к определённому программистом типу Dist мы используем конструктор с одним аргументом Dist(float m)…. Такого рода конструкторы иногда называют конструкторами преобразования. Этот конструктор вызывается, когда создаётся объект класса Dist с одним аргументом. Для перехода от определённого программистом типа Dist к основному типу float (в данной программе) используется метод преобразования. Этот метод принимает значение объекта класса Dist, преобразовывает его в значение типа float, представляющее собой метры, и возвращает это значение.

 

Преобразование объектов классов в объекты других классов

При преобразовании объектов одного класса в объекты другого класса применяются те же два способа преобразования, что и для преобразований между основными типами и объектами определённых пользователем классов, т.е. используется конструктор с одним аргументом или операция преобразования. Выбор зависит от того, хотите ли вы записать функцию преобразования в классе для исходного объекта или для объекта назначения. Если процедура преобразования записана в классе назначения, то используется конструктор, если процедура в исходном классе, то применяется операция преобразования. Класс назначения - это класс, объект которого получает значение. Например, записано object_a=object_b;, где object_a – объект класса А (это класс назначения), а object_b – объект класса В.

Рассмотрим программу, в которой производятся преобразования между двумя способами исчисления времени: 12-часовым и 24-часовым. На этом примере рассмотрим случай, когда функция преобразования расположена в исходном классе, следовательно исходя из упомянутого выше правила реализуем преобразование объекта одного класса в объект другого класса в виде операции (метода) преобразования.

class Time12 {

private:

bool pm; int hrs; int mins;

public:

Time12(): pm(true), hrs(0), mins(0)

{ }

Time12(bool ap, int h, int m): pm(ap), hrs(h), mins(m)

{ }

void display() const {

cout << hrs << ':';

if (mins < 10) cout << '0';

cout << mins << ' ';

string am_pm = pm? "p.m.": "a.m.";

cout << am_pm;

}

};

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

class Time24 {

private:

int hours; int minutes; int seconds;

public:

Time24(): hours(0), minutes(0), seconds(0)

{ }

Time24(int h, int m, int s): hours(h), minutes(m), seconds(s)

{ }

void display() const {

if (hours < 10) cout << '0';

cout << hours << ':';

if (minutes < 10) cout << '0';

cout << minutes << ':';

if (seconds < 10) cout << '0';

cout << seconds;

}

operator Time12() const;

};

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

Time24::operator Time12() const {

int hrs24 = hours;

bool pm = hours < 12? false: true;

int roundMins = seconds < 30? minutes: minutes + 1;

if (roundMins == 60) {

roundMins = 0;

++hrs24;

if (hrs24 == 12 || hrs24 == 24) pm = (pm == true)? false: true;

}

int hrs12 = (hrs24 < 13)? hrs24: (hrs24 - 12);

if (hrs12 == 0) {

hrs12 = 12;

pm = false;

}

return Time12(pm, hrs12, roundMins);

}

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

int main() {

int h, m, s;

 

while (true) {

cout << "Vvedite vremja v 24 formate: \n";

cout << " Chasy (от 0 до 23): "; cin >> h;

if (h > 23) return (1);

cout << " Min: "; cin >> m;

cout << " Sek: "; cin >> s;

 

Time24 t24(h, m, s); // присвоили объекту значения, введенные с клав.

cout << "Ishodnoe vremja: "; t24.display();

 

Time12 t12 = t24; // преобразование

 

cout << "\nV 12-chas formate: "; t12.display();

cout << "\n\n";

}

return 0;

}

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

Функция Time24::operator Time12() const преобразует вызывающий её объект t24 в объект класса Time12 и возвращает его в главную функцию.

Если функция преобразования находится в классе назначения, то необходимо использовать конструктор с одним аргументом. В этом случае мы должны были в классе Time12 написать конструктор с 1 аргументом Time12(Time24) и метод Time12::Time12(Time24 t24).

 

Лекция 7 (15 стр.)

НАСЛЕДОВАНИЕ

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

 
 

 

 


Производный класс     Свойства А и Б доступны

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

На одном из прошлых занятий мы разбирали класс Count, в котором использовалась перегруженная операция ++. Допустим теперь нам необходимо, не изменяя этот класс, создать метод для уменьшения счётчика. Допустим на создание и тестирование класса Count было затрачено много времени и желание его не изменять вполне очевидно. Или мы просто не имеем доступа к исходному коду класса, например, если он распространяется как часть библиотеки классов. В этих случаях целесообразно использовать наследование для создания производных классов.

class Count { //áàçîâûé êëàññ

protected:

int c;

public:

Count() { c=0; }

Count(int t) { c=t; }

int get() const {

return c;

}

Count operator++() {

++c;

return Count(c);

}

};

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

class CountPr: public Count { // ïðîèçâîäíûé êëàññ

public:

Count operator--() {

--c;

return Count(c);

}

};

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

int main() {

CountPr c1; // îáúåêò ñ1 ïðîèçâîäíîãî êëàññà

cout << "\n c1=" << c1.get();

++c1; ++c1; ++c1;

cout << "\n c1=" << c1.get();

--c1; --c1;

cout << "\n c1=" << c1.get();

getch(); return 0;

}

В данной программе определён новый производный класс CountPr, который включает в себя новый метод уменьшения счётчика и в тоже время наследует (использует) все возможности базового класса Count (его конструкторы и методы).

Строка class CountPr: public Count определяет, что класс CountPr является наследником базового класса. Ключевое слово public определяет, что объект производного класса может иметь доступ к методам базового класса, объявленным как public. Если используется ключевое слово private, то для объектов производного класса нет доступа к членам базового класса.

При создании объекта с1 производного класса происходит его инициализация нулевым значением несмотря на то, что в классе CountPr нет конструктора. Здесь работает принцип – если конструктор производного класса не определён, то будет использоваться подходящий конструктор базового класса. В данном случае используется конструктор без аргументов базового класса Count. Таким образом, использование доступного метода взамен отсутствующего – обычная ситуация, возникающая при наследовании. Действительно, объект с1 класса CountPr, не находя методы в своём классе, использует необходимые методы из базового класса.

Вывод программы:

С1=0

С1=3

С1=1

В данной программе переменная c имеет спецификатор доступа protected. Рассмотрим его предназначение. Методы производного класса имеют доступ к членам (полям и методам) базового класса, если последние имеют спецификатор доступа public или protected. К членам, объявленным как private, доступа нет. Если бы поле count было бы объявлено как public, то это разрешило бы доступ к переменной c из любой функции программы, уничтожив тем самым возможность сокрытия данных. Таким образом, член, объявленный как protected, доступен методам своего класса и методам любого производного класса, но при этом он не будет доступным из функций, не принадлежащих этим классам, например из функции main(). Приведём таблицу, отражающую возможности использования спецификаторов доступа в различных ситуациях.

 

Таблица 1. Наследование и доступ

Спецификатор доступа Доступ из самого класса Доступ из производных классов Доступ из внешних классов и функций
public Есть Есть Есть
protected Есть Есть Нет
private Есть Нет Нет

 

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

Необходимо помнить, что наследование не работает в обратном направлении. Базовому классу и его объектам недоступны производные классы. То есть, если создать объект с2 класса Count, то он не сможет использовать метод operator--() класса CountPr, а объект производного класса может использовать все методы, как базового класса, так и производного.



Поделиться:


Последнее изменение этой страницы: 2016-04-08; просмотров: 672; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 44.211.49.158 (0.034 с.)