Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Figure 4.5 Class Hierarchy Showing Multiple Inheritance




A pointer to an object of type D can be safely cast to B or C. However, if D is cast to point to an A object, which instance of A would result? This would result in an ambiguous casting error. To get around this problem, you can perform two unambiguous casts. For example:

void f(){ D* pd = new D; A* pa = dynamic_cast<A*>(pd); // error: ambiguous B* pb = dynamic_cast<B*>(pd); // first cast to B A* pa2 = dynamic_cast<A*>(pb); // ok: unambiguous}

Further ambiguities can be introduced when you use virtual base classes. Consider the class hierarchy shown in Figure 4.6:

Figure 4.6 Class Hierarchy Showing Virtual Base Classes

In this hierarchy, A is a virtual base class. See Virtual Base Classes for the definition of a virtual base class. Given an instance of class E and a pointer to the A subobject, a dynamic_cast to a pointer to B will fail due to ambiguity. You must first cast back to the complete E object, then work your way back up the hierarchy, in an unambiguous manner, to reach the correct B object.

Consider the class hierarchy shown in Figure 4.7:

Figure 4.7 Class Hierarchy Showing Duplicate Base Classes

Given an object of type E and a pointer to the D subobject, to navigate from the D subobject to the left-most A subobject, three conversions can be made. You can perform a dynamic_cast conversion from the D pointer to an E pointer, then a conversion (either dynamic_cast or an implicit conversion) from E to B, and finally an implicit conversion from B to A. For example:

void f(D* pd){ E* pe = dynamic_cast<E*>(pd); B* pb = pe; // upcast, implicit conversion A* pa = pb; // upcast, implicit conversion}

The dynamic_cast operator can also be used to perform a “cross cast.” Using the same class hierarchy, it is possible to cast a pointer, for example, from the B subobject to the D subobject, as long as the complete object is of type E.

Considering cross casts, it is actually possible to do the conversion from a pointer to D to a pointer to the left-most A subobject in just two steps. You can perform a cross cast from D to B, then an implicit conversion from B to A. For example:

void f(D* pd){ B* pb = dynamic_cast<B*>(pd); // cross cast A* pa = pb; // upcast, implicit conversion}

A null pointer value is converted to the null pointer value of the destination type by dynamic_cast.

When you use dynamic_cast < type-id > (expression), if expression cannot be safely converted to type type-id, the run-time check causes the cast to fail. For example:

class A {... }; class B {... }; void f(){ A* pa = new A; B* pb = dynamic_cast<B*>(pa); // fails, not safe; // B not derived from A...}

The value of a failed cast to pointer type is the null pointer. A failed cast to reference type throws a bad_cast exception.

 

Преобразования типов, определенных в программе

Конструктор с одним аргументом можно явно не вызывать.

#include "iostream.h"

Class my_class

{ double x,y; //

public:

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

double summa();

};

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

void 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;

}

В рассматриваемом примере все три создаваемых объекта будут инициализированы числом 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.h"

Class my_cl1

{ double x; //

public:

operator double(){return x;}

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; }

void main()

{ fun(12); // ERROR cannot convert parameter 1

// from 'const int' to 'class my_cl2'

fun(my_cl2(12)); // подразумеваемое преобразование типа

}

В этом случае для инструкции 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))

В заключение отметим основные правила доопределения операторов:

- все операторы языка С++ за исключением. *::?: sizeof и символов # ## можно доопределять;

- при вызове функции operator используется механизм перегрузки функций;

- количество операндов, которыми оперируют операторы (унарные, бинарные), и приоритет операций сохраняются и для доопределенных операторов.

Шаблоны

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...