Разделы презентаций


Приведение типов и контейнеры

Содержание

В С++ дополнительно ввели именованные операторы преобразования типов: Преобразования типов в С++ const_cast < > ( ) static_cast < > ( ) reinterpret_cast < > ( ) dynamic_cast < > (

Слайды и текст этой презентации

Слайд 1В языке С явное приведение типов осуществлялось при заключении типа

в круглые скобки, так называемое "приведение в круглых скобках"
Например, преобразование

double --> int:

Преобразования типов в С

int i = (int) 2.5;

такая форма приведения не наглядна
при приведении пользовательских типов могут возникать ошибки

Cls1 * a = ...;
Cls2 * b = (Cls2 *) a;

Для некоторых типов могут возникать неопределенности. Cls1 и Cls2 могут быть никак не связаны, и тогда операция присвоения не правомочна. В целом надо различать преобразования связанных типов и несвязанных типов.


Слайд 2В С++ дополнительно ввели именованные операторы преобразования типов:

Преобразования типов

в С++
const_cast < > ( )
static_cast

> ( )
reinterpret_cast < > ( )
dynamic_cast < > ( )
В С++ дополнительно ввели именованные операторы преобразования типов: Преобразования типов в С++ const_cast < > ( )

Слайд 4Предположим, что мы хотим в массиве типа A определена функция


Слайд 5Оператор reinterpret_cast предназначен для приведения друг к другу указателей, которые

друг от друга не зависят:



кроме того , с его помощью

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

Преобразование reinterpret_cast <> ()

int * p = ...;
double * d = reinterpret_cast(p);

Оператор reinterpret_cast предназначен для приведения друг к другу указателей, которые друг от друга не зависят:кроме того ,

Слайд 6Оператор reinterpret_cast не меняет константности.
Оператор reinterpret_cast является жестко машинно-зависимым.

Чтобы безопасно его использовать, надо хорошо понимать, как именно реализованы

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

Преобразование reinterpret_cast <> () - 2

Оператор reinterpret_cast не меняет константности. Оператор reinterpret_cast является жестко машинно-зависимым. Чтобы безопасно его использовать, надо хорошо понимать,

Слайд 7Оператор static_cast предназначен для проведения преобразований между связанными значениями. Связанность

проверяется на этапе компиляции, поэтому и называется static.
Типы, к которым

применим static_cast:

Преобразование static_cast <> ()

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

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

Слайд 8Числовые типы :
Типы, связанные наследованием, а также ссылки и указатели


Слайд 9Пользовательские преобразования :
Это эквивалентно
Следует отметить, что проведение подобных преобразований не

всегда безопасно, поскольку при выполнении контроль отсутствует
Преобразование static_cast ()

– 3

static_cast("Hello");

class B { };
class D : public B { };
void f(B* pb, D* pd)
{
D* pd2 = static_cast(pb); // pb может указывать не только на B
B* pb2 = static_cast(pd); // безопасно
}

string("Hello"); // Вызов конструктора

Преобразование к void*: можно преобразовать любой указатель к void * и обратно.

Пользовательские преобразования :Это эквивалентноСледует отметить, что проведение подобных преобразований не всегда безопасно, поскольку при выполнении контроль отсутствуетПреобразование

Слайд 10Только объявим классы
Преобразование static_cast () – пример
struct A;
struct

B;
struct D;
A * a = ...;
B *

b = static_cast(a); // Не скомпилируется
B * b = (B *)a; // Это сработает как reinterpret_cast
// Мы не сдвинем указатель, но компилятор не выдаст ошибки

Если же помимо объявления будут определения классов, то static_cast сработает правильно.

Замечание: Если приводим встроенные типы, то это можно делать по старому, в стиле С, в остальных случаях надо использовать C++ операторы преобразования типов.

Только объявим классыПреобразование static_cast () – примерstruct A; struct B; struct D; A * a = ...;

Слайд 11RTTI позволяет программам, которые используют указатели или ссылки на базовые

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

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

RTTI - Run-Time Type Information

Оператор typeid, которые возвращает фактический тип объекта, к которому относится указатель или ссылка.
Оператор dynamic_cast, который осуществляет безопасное преобразование указатели или ссылки на базовый класс в указатель или сссылку на произвольный класс

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

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

Слайд 12Оператор typeid имеет следующий формат:
Оператор typeid
#include
type_info -

структура, позволяющая получить некоторую информацию о типе
typeid(e)
здесь е - это

любое выражение или имя класса

Результатом операнда typeid является ссылка на объект библиотечного типа type_info.
Чтобы использовать класс type_info, необходимо подключить библиотечный заголовок typeinfo:

Оператор typeid имеет следующий формат:Оператор  typeid #include type_info - структура, позволяющая получить некоторую информацию о типеtypeid(e)здесь

Слайд 13Действия, которые можно производить с объектами типа type_info:
Операции с типом

typeinfo
Сравнение на равенство ==
Сравнение на неравенство !=
name()

- возвращает символьную строку в стиле С, содержащую отображаемую версию имени типа. Может вернуть пустую строку, что не очень хорошо.
before() - возвращает логическое значение, указывающее на то, следует ли один тип прежде другого. Порядок следования зависит от компилятора. Т.е. с помощью этого метода типы можно упорядочить.
Действия, которые можно производить с объектами типа type_info:Операции с типом typeinfo Сравнение на равенство == Сравнение на

Слайд 14A * a = new C();
type_info ti = typeid(*

a); // Передается ссылка на объект
ti.name();

// "C"

Как работает typeid

typeid(int) - определяется в момент компиляции

typeid(A) - определяется в момент компиляции // "A"

typeid(a) - определяется в момент компиляции // "A * "

typeid(* a) - действие времени выполнения.
Для того чтобы это действие действительно было временем выполнения класс А должен обладать полиморфизмом (должно быть наличие виртуальной функции), иначе вернет "A"

if (typeid(*a)== typeid(A))… // Пример использования

A * a = new C(); type_info ti = typeid(* a); // Передается ссылка на объект ti.name();

Слайд 15if (Circle * c = dynamic_cast(a))
{
... // Первая

фигура - круг
}
Преобразование dynamic_cast < > ( )
A *

a = new C();
B * b = dynamic_cast(a); // Вернет 0

Использование оператора dynamic_cast при программировании

Преобразование указателей с помощью dynamic_cast

B & b = dynamic_cast(* a);
// В случае неудачи бросит исключение

Преобразование ссылок с помощью dynamic_cast

dynamic_cast обеспечивает механизм, который проверяет правомерность преобразований в процессе выполнения.
Этот тип преобразований называют «upcast» (подброс), поскольку он перемещает указатель по иерархии классов от производного до его предка.
dynamic_cast - проверка при выполнении делается для того, чтобы определить реальный тип преобразуемого выражения.

if (Circle * c = dynamic_cast(a)) { ... // Первая фигура - круг }Преобразование dynamic_cast < >

Слайд 16#include
using namespace std;
class B { };
class C : public

B { };
class D : public C { };

void f(D*

pd) {
C* pc = dynamic_cast(pd); // ok: C is a direct base class
// pc points to C subobject of pd
B* pb = dynamic_cast(pd); // ok: B is an indirect base class
// pb points to B subobject of pd
}
void main(int argc, char * argv[])
{
D* pd;
f(pd);
}

Преобразование dynamic_cast < > - пример 1

#include using namespace std;class B { };class C : public B { };class D : public C

Слайд 17#include
using namespace std;
struct B {virtual void f();};
struct A :

public B {};

void B::f() {
A* pa = new

A;
B* pb = new B;
void* pv = dynamic_cast(pa); // pv now points to an object of type A
pv = dynamic_cast(pb); // pv now points to an object of type B
}

void main(int argc, char * argv[])
{
A a;
a.f();
}

Преобразование dynamic_cast < > - пример 2

#include using namespace std;struct B {virtual void f();};struct A : public B {};void B::f() {  A*

Слайд 18#include
using namespace std;
class B {public: virtual void f();};
class D

: public B {public: virtual void f();};

void B::f() {

B* pb = new D; // unclear but ok
B* pb2 = new B;

D* pd = dynamic_cast(pb); // ok: pb actually points to a D
D* pd2 = dynamic_cast(pb2); // pb2 points to a B not a D
}
void D::f() {}

void main(int argc, char * argv[])
{
B b;
b.f();
}

Преобразование dynamic_cast < > - пример 3

#include using namespace std;class B {public: virtual void f();};class D : public B {public: virtual void f();};void

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



Контейнеры в С++
Множество операций с контейнерными классами включает в себя

возможность легко получить доступ к индивидуальным элементам. Классы также являются средствами достижения абстракции в С++. Абстракция – это возможность игнорирования подробностей. Абстракция и инкапсуляция – близнецы-братья.
Классы скрывают подробности и обеспечивают внешние удобные способы обработки вычислительных задач.
Контейнерами называются классы, предназначенные для размещения большого количества индивидуальных элементов. Контейнеры в С++Множество операций с контейнерными классами

Слайд 20Несмотря на разнообразие внутренней организации контейнерных классов, можно определить группу

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

основные операции

Операция организации контейнера (конструктор)
Операция внесения в контейнер нового элемента (set)
Операция чтения элемента из контейнера (get)
Операция пополнения контейнера новым элементом (add)
Операция удаления заданного элемента из контейнера (remove)
Операция очистки всего содержимого контейнера (clear)

Именно эти операции чаще всего должны быть переопределены при использовании некоторых «стандартных» базовых классов или определены при создании собственных контейнерных классов.

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

Слайд 21Контейнерные классы в MFC называются коллекциями. Все коллекции по способу

внутренней организации поделены на три вида:
Контейнерные классы в MFC
list (список)

– этот класс обеспечивает упорядоченный, неиндексируемый список элементов, базирующийся на двунаправленном списке. Список имеет «голову» и «хвост» и добавляет и удаляет элементы с головы или хвоста списка. Часто используются операции вставки и удаления элементов из середины списка.
array (массив) – этот класс обеспечивает динамически изменяемый по размеру , упорядоченный и индексируемый целыми числами массив некоторых объектов.
map (отображение) – это класс, в котором каждый из объектов ассоциируется с некоторым ключевым значением. Этот класс еще иногда называют словарем (dictionary)

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

Контейнерные классы в MFC называются коллекциями. Все коллекции по способу внутренней организации поделены на три вида:Контейнерные классы

Слайд 22Классы коллекций, не использующих шаблоны, приведены в таблице:
Классы коллекций в

Классы коллекций, не использующих шаблоны, приведены в таблице:Классы коллекций в MFC

Слайд 23Классы коллекций с использованием шаблонов, приведены в таблице:
Классы коллекций в

Классы коллекций с использованием шаблонов, приведены в таблице:Классы коллекций в MFC

Слайд 24Основные свойства коллекций, определяемые их видом:
Классы коллекций в MFC –

общие свойства

Основные свойства коллекций, определяемые их видом:Классы коллекций в MFC – общие свойства

Слайд 25Коллекция – пример (начало)
#include
using namespace std;
class vct {

int *p; // базовый указатель

int size; // число элементов
int maxsize; // размер занятой памяти
int crt; // текущий элемент
public:
vct(int n); // Конструктор
~vct() { delete [] p; } // Деструктор
inline int getsize() // Взять размер массива
{ return size;}
int& operator[] (int i); // Индексатор a[i]
int& get(int i); // Доступ для чтения
void set(int i, int val); // Доступ для записи
int add(int val); // Пополнение
int remove(int i); // Удаление
void clear(); // Очистка
int& next(); // Читать с переходом на следующий
int& prev(); // Читать с переходом на предыдущий
};

Рассмотрим класс vct, предназначенный для хранения целых чисел в форме индексируемого массива.

Коллекция – пример (начало)#include using namespace std;class vct {  int *p;     //

Слайд 26Коллекция – пример
vct::vct(int n=10) //-------------------------------- Конструктор
{
maxsize =n;

crt = size=0; p = new int [n];
}


int& vct::operator[]

(int i) //----------------------- Индексатор a[i]
{
if ( i < 0 || i >= size) {
cout << "Size???\n";
exit(1);
}
return p[i];
}

Продолжение 1 …

Коллекция – примерvct::vct(int n=10)  //-------------------------------- Конструктор{  maxsize =n; crt = size=0; p = new int

Слайд 27Коллекция – пример
int& vct::get(int i)

// -------------------------------- Доступ для чтения
{
if ( i

i>=size) {
cout << "Size???\n"; exit(1);
}
return p[i];
}
void vct::set(int i, int val) //-------------------------------- Доступ для записи
{
if (i < 0 || i>=10000) { // так решили
cout << "Size???\n"; exit(1);
}
if (i >= maxsize) {
maxsize = i+10;
int * pnew= new int[maxsize+10];
memcpy(pnew, p, size* sizeof(int));
delete [] p;
p = pnew;
}
if (i < size) size = i;
p[i] = val;
}

Продолжение 2 …

Коллекция – примерint& vct::get(int i)      // -------------------------------- Доступ для чтения{  if

Слайд 28Коллекция – пример
int vct::add(int val) //----------------------------------

Пополнение
{
if (size >= maxsize) {
if

(maxsize>=10000) { // Мы так решили
cout << "Size???\n";
exit(1);
}
maxsize = size+10;
int * pnew= new int[maxsize];
memcpy(pnew, p, size* sizeof(int));
delete [] p;
p = pnew;
}
p[size++] = val;
return size;
}

Продолжение 3 …

Коллекция – примерint vct::add(int val)     //---------------------------------- Пополнение{  if (size >= maxsize) {

Слайд 29Коллекция – пример
int vct::remove(int i) //--------------------------------

Удаление
{
if (i size-1)

return -1; // Игнорируем выполнение
if (i < size-1)
memcpy(&p[i],&p[i+1], (size-i+1) * sizeof(int));
size--;
return i;
}
void vct::clear() //----------------------------------- Очистка
{
if (maxsize >10) {
maxsize = 10;
delete [] p;
p = new int[10];
}
crt = size = 0;
}

Продолжение 4 …

Коллекция – примерint vct::remove(int i)     //-------------------------------- Удаление {  if (i size-1)

Слайд 30Коллекция – пример
int& vct::next()

//------------------- Читать С ПЕРЕХОДОМ НА следующий
{
if (size==0)

{
cout << "Size???\n"; exit(1);
}
if (crt >= size) return (p[crt=0]);
else return (p[crt++]);
}

int& vct::prev() //-------------------- Читать С ПЕРЕХОДОМ НА предыдущий
{
if (size==0) {
cout << "Size???\n"; exit(1);
}
if (crt == 0) {
crt=size-1;
return (p[0]);
}
else
if (crt > size-1) crt = size-1;
return (p[crt--]);
}

Продолжение 5 …

Коллекция – примерint& vct::next()        //------------------- Читать С ПЕРЕХОДОМ НА следующий{

Слайд 31Коллекция – пример
void main() {
vct v;
int i;
for

(i=0; i < 9; i++) v.add(i);

v.remove(5);
cout

for (i=0; i < v.getsize(); i++)
cout << v.next()<<" ";
cout << endl;

for (i=v.getsize()-1; i > -1; i--)
cout << v.prev()<<" ";
cout << endl;

char s; std::cin>>s;
}

Продолжение 6 …


Результат:

Новые методы:
позиционирование…,
покажи текущий…
Разделение текущих по next и prev

Коллекция – примерvoid main() { vct v; int i; for (i=0; i < 9; i++)

Слайд 32Коллекция – итераторы
. . .
friend vct_iter;
. . .
class vct_iter

{
private:
vct* pv; // Базовый указатель на контейнер

int crt; // Индекс обращения
public:
vct_iter(vct& v): crt(0), pv(&v) { }
int& next();
};

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

Коллекция – итераторы . . .friend vct_iter;. . .class vct_iter {private:  vct* pv;  // Базовый

Слайд 33Коллекция – итераторы -продолжение
int& vct::next()
{
if (crt

== pv -> size)
return (pv -> p[crt

= 0]); // на 1-й элемент
else
return (pv -> p[crt++]); // на следующий
}

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

Коллекция – итераторы -продолжение int& vct::next(){  if (crt == pv -> size)   return (pv

Обратная связь

Если не удалось найти и скачать доклад-презентацию, Вы можете заказать его на нашем сайте. Мы постараемся найти нужный Вам материал и отправим по электронной почте. Не стесняйтесь обращаться к нам, если у вас возникли вопросы или пожелания:

Email: Нажмите что бы посмотреть 

Что такое TheSlide.ru?

Это сайт презентации, докладов, проектов в PowerPoint. Здесь удобно  хранить и делиться своими презентациями с другими пользователями.


Для правообладателей

Яндекс.Метрика