Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lutsik_Yu_A_Obektno_orientir_programmir_na_yaz.pdf
Скачиваний:
63
Добавлен:
11.05.2015
Размер:
4.33 Mб
Скачать

 

 

а

Вначале выполняется попытка использов ть стандартные преобразования

типов. Если это невозможно, то компилятор используетБпреобразования, опре-

деленные пользователем.

к

(тип) выражение.

нное

 

5.3.1. Явные преобразования типов

 

Явное приведение типа, выполн

в стиле языка С, имеет вид

деструктор A

 

 

перегрузка operator DELETE

 

 

перегрузка operator NEW

 

 

конструктор A

 

 

конструктор В

 

 

деструктор В

 

 

деструктор A

перегрузка operator DELETE

При public-наследовании класса А классом В public-функции new и delete

наследуются как public-функции класса В. Отметим, что необходимость исполь- зования в данном примере виртуального деструктора рассмотрена ранее.

5.3. Преобразование типа Р

Выражения, содержащиеся в функциях и используемые для вычисления

некоторого значения, записываются в большинстве случаев с учетом коррект-

ности по отношению к объектам этого выражения. В то же время,Иесли исполь-

зуемая операция для типов величин, участвующих в выражении, явно не опре-

 

У

делена, то компилятор пытается выполнить такое преобразование типов в два

этапа.

Г

 

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

ние выражения будет пре браз вано к данному типу. Например:

int a = (int) b;

 

 

т

char *s=(char *) addr;

о

Недостатком их яв яется полное отсутствие контроля, что приводит к

 

и

 

ошибкам и путанице. Существует большая разница между приведением указа-

неплохоБболееприточно определять цель каждого приведения. Чтобы преодолеть недостатки приведения типов, выполняемых в стиле языка С, в язык С++ вве-

теля на const-о ъект к указателю на не const-объект (изменяется только атрибут

объекта)

л

ведением указателя на объект базового класса к указателю на

 

б

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

дены четыре оператора приведения типа: static_cast, const_cast, reinterpret_cast и dynamic_cast. Спецификация преобразования имеет следующий вид:

оператор_приведения _типа<тип> (выражение).

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

124

5.3.2. Преобразования типов, определенных в программе
Конструктор с одним аргументом можно явно не вызывать.
#include <iostream> using namespace std;
class my_class
{ double x,y; // public:

ко указателя на базовый класс к указателю на производный, но и наоборот. int i,j;

double d=static_cast<double>(i)*j;

В то же время, например, преобразование int к int* (и обратно) приведет к ошибке компиляции. Рассматриваемые далее операторы приведения использу- ются для более узкого круга задач. Для преобразований не связанных между собой типов используется reinterpret_cast.

int i;

void *adr= reinterpret_cast<void *> (i);

Необходимо отметить, что reinterpret_cast не выполнит преобразование таких типов как float, double-объектов к типу указателя.

Если же нужно выполнить преобразование выражения, имеющего тип с

атрибутами const и volatile, к типу без них, и наоборот, то можноРиспользовать

оператор const_cast:

У

Г

И

const char *s;

char *ss=const_cast<char*> (s);

 

 

Следующий оператор dynamic_cast предназначен для приведения указате-

ля или ссылки на объект базового класса к указателям или ссылкам на объекты

 

 

 

 

 

 

 

а

производных классов. При этом можно определить, была ли попытка приведе-

ния типа успешной. В результате неуд чнойБпопытки преобразования возвра-

 

 

 

 

 

 

 

к

щается либо нулевой указатель, либо возник ет исключение (при преобразова-

нии ссылок).

 

 

 

 

 

 

class A { . . . };

т

 

 

class B : public A { . . .};

 

 

class C : public B { . .

е.};

 

int main()

о

 

 

 

 

 

и

 

 

 

 

{ A *pa;

 

 

 

 

 

 

B *pb;

 

 

 

 

 

 

л

 

 

 

 

 

 

C *pc;

 

 

 

 

 

б

 

 

 

 

 

 

 

. . .

 

 

 

 

 

и

pa= dynamic_cast<A*>(pc);

pb= dynamic_cast<B*>(pc);

 

 

Б

}

return 0;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

125

my_class(double X){x=X; y=x/3;} double summa();

};

double my_class::summa() { return x+y; } int main()

{double d;

my_class my_obj1(15), // создание объекта obj1 и инициализация его

my_obj2=my_class(15),

// создание объекта obj2 и инициализация его

my_obj3=15;

Р

// создание объекта obj3 и инициализация его

 

d=my_obj1; // error no operator defined which takes a right-hand operand of

 

 

 

 

И

 

// type 'class my_class' (or there is no acceptable conversion)

 

cout << my_obj1.summa() << endl;

 

У

 

cout << my_obj2.summa() << endl;

 

 

 

 

 

 

cout << my_obj3.summa() << endl;

Г

 

}

return 0;

 

Б

 

 

 

 

 

 

 

 

 

В рассматриваемом примере все три создаваемых объекта будут инициа-

лизированы числом 15 (первые два явным, третий неявным вызовом конструк-

 

 

 

 

 

 

 

 

а

 

тора). Следовательно, значение базовой переменной (определенной в языке)

может быть присвоено переменной типа, определенного пользователем.

Для выполнения обратных преобразов ний, т.е. от переменных,

имеющих

 

 

 

 

 

 

 

е

 

 

тип, определенный пользователем к базовому типу, можно задать преобразова-

ния с помощью соответствующей функциикoperator(), например:

 

class my_class

 

 

т

 

 

 

 

 

 

 

 

{

double x,y;

 

о

 

 

 

public:

 

 

 

 

 

 

 

 

и

 

 

 

 

};

 

 

 

 

 

 

 

 

operator double() {return x;}

 

 

 

 

my_class(double X){x=X; y=x/3;}

 

 

 

 

 

л

 

 

 

 

 

 

double summa();

 

 

 

 

 

 

 

б

 

 

 

 

 

 

Теперь в выражении d=my_obj1 не будет ошибки, так как мы задали пря-

 

и

 

 

 

 

 

 

 

мое преобразован е типа. При выполнении этой инструкции активизируется

Б

 

 

 

 

 

 

 

и возвра-

функция operator, преобразующая значение объекта к типу double

щающая значен е компоненты объекта. Наряду с прямым преобразованием в С++ имеется подразумеваемое преобразование типа

#include <iostream> using namespace std;

class my_cl1

 

{ double x;

//

public:

 

operator double(){return x;}

126

my_cl1(double X) : x(X) {}

};

 

 

 

 

 

 

class my_cl2

 

 

 

 

 

{

double x;

//

 

 

 

 

 

public:

 

 

 

 

 

 

operator double(){return x;}

 

 

 

 

};

my_cl2(my_cl1 XX): x(XX) {}

 

 

 

 

 

 

 

 

 

Р

void fun(my_cl2 YY)

 

 

 

 

 

 

 

 

 

{ cout << YY <<endl; }

 

 

 

И

int main()

 

 

 

 

 

 

 

 

{

fun(12);

// ERROR cannot convert parameter 1

}

 

 

 

У

 

 

 

// from 'const int' to 'class my cl2'

 

fun(my_cl2(12));

// подразумеваемое преобразование типа

 

return 0;

 

Г

 

 

 

 

 

Б

 

 

 

В этом случае для инструкции fun(my cl2(12)) выполняется следующее:

активизируется конструктор кл

my cl1 (x инициализируется значени-

ем 12);

 

 

 

 

 

 

при выполнении в констру торе my cl2 инструкции x(XX) вызывается

функция operator (класса my cl1), возвр щ ющая значение переменной x, пре-

образованное к типу double;

е

асса

 

 

далее при выполнении

инструкции cout << YY вызывается функция

operator() класса my_cl2, выполняющая преобразование значения объекта YY к

типу double.

 

но

 

 

 

 

 

 

Разрешается вып лня ь олько одноуровневые подразумеваемые преоб-

 

 

 

при

 

 

разования. В

 

веденнтм выше примере

инструкция fun(12) соответствует

 

 

л

 

му преобразованию, где первый уровень − my_cl1(12) и

двухуровневому неяв

второй − my cl2(my cl1(12)).

 

 

Вопросы и упражнения для закрепления материала

и

Можно ли перегрузить функции следующего вида:

Б

1.

бvoid fun( int );

void fun( int & );

void fun( int * );

 

2.

Можно ли перегружать в классе функции-члены класса?

 

3.

Можно ли перегружать деструкторы?

 

4.

Можно ли перегружать статические функции?

 

5.

Можно ли перегружать виртуальные функции?

 

6.

Можно ли переопределить в классе функции-члены?

 

7.

Почему может потребоваться перегрузка оператора присваивания?

 

8.

Можно ли изменить приоритет перегруженного оператора?

 

9.

Когда следует переопределять операторы с помощью дружественных

функций, а когда с помощью функций элементов класса?

127

10. Могут ли члены-данные класса иметь атрибут const? Как инициали- зировать эти члены?

11. Могут ли статические члены класса иметь атрибут private? Как ини- циализировать такие члены-данные?

12. Возникнут ли ошибки при компиляции данной программы, если нет,

то что она выведет на экран?

 

 

 

 

 

#include <iostream>

 

 

 

 

 

using namespace std;

 

 

 

 

 

int operator+(int a, int b)

 

 

 

 

Р

{return 5;}

 

 

 

 

int main()

 

 

 

 

{ int a=1,b=1;

 

 

 

 

 

 

 

 

 

 

 

 

 

И

 

 

 

У

 

13. Для созданного объекта a, разработанного классавектора (одномер-

ный массив), реализовать перегрузку

операции

* (операция разадресации)

(*a=n). Содержимое объекта а (одномерный

Г

 

 

ив) до и после выполнения

операции вывести на экран.

 

Б

 

 

 

14. Создать несколько объектов

a, b и с р зр ботанного класса. Класс

символьная строка. Для создания объ ктов a и b используются конструкторы с

 

 

масс

параметром, с конструктор без параметров. Реализовать для объектов данного

 

к

класса перегрузку операции + (с=a+b) сл дующим образом:

- объекты a и b не должны измени ь своего значения, а c содержит стро-

 

е

 

ку сумма строк объектов a и b;

 

- объект b не должен змени ь своего значения, к строке объекта а доба-

вить строку объекта b, затем с держимоетобъекта a присвоить объекту c;

- объект b не д

енозменить своего значения, а к строке объекта а до-

бавить строку о ъекта b, в объекте c сохранить исходное значение объекта a.

 

 

и

Содержимое о ъектов a,b,c (их строк) до и после выполнения операции

вывести на экран. олж

15. Определите класс FLOAT, который ведет себя аналогично float. Под-

сказка: опреде

б

 

те FLOAT::operator float().

16. Даны определения переменных:

ли

 

char cl;

int i; dloat f; double d;

Б

 

 

Какие неявные преобразования типов будут выполнены?

(a)c = 'a' + 3;

(b)f = ui i * 1.0;

(c)d = ui * f;

(d)c = i + f + d;

128

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