MyTetra Share
Делитесь знаниями!
Приведение типов в C++. Терминология, динамический полиморфизм
Время создания: 01.04.2016 23:35
Автор: xintrea
Текстовые метки: приведение, преобразование, типы, C++, термины, cast, upcast, downcast, rtti, динамический полиморфизм
Раздел: Компьютер - Программирование - Язык C++ (Си++)
Запись: xintrea/mytetra_syncro/master/base/1459542913fsh21p6min/text.html на raw.github.com

Если происходит приведение типа-наследника к одному из базовых типов, то это называется upcast. При таком приведении использование методов вида static_cast/dynamic_cast не требуется.


Обратное действие, когда происходит приведение базового типа к типу-наследнику, называется downcast. При таком приведении явный вызов методов xxx_cast обязателен.


При downcast вопрос только в том, какой каст применить. Быстрее - static_cast, но программист должен точно знать, что указатель/ссылка указывает на объект конкретного типа. Если программист ошибется - в рантайме может произойти все, что угодно. Если же программист не может знать, на что указывает указатель (например, метод возвращает объекты разных производных типов? уточнить) - придется использовать dynamic_cast, но он работает медленнее, ибо это элемент механизма RTTI (динамическая идентификация типа данных, Real Time Type Identification).


Примечание: в механизме RTTI, в принципе, имеется всего два инструмента: dynamic_cast<>() и typeid().


Пример кода:



// Объект Qt-класса QAbstractItemModel

QAbstractItemModel *base;


// Объект класса, унаследованного от QAbstractItemModel

TreeModel *child = new TreeModel;


// Upcast

base = child; // так можно (ибо child содержит все данные для base и даже больше)


// Downcast

child = base; // так, без преобразования, нельзя (base не имеет всех данных для child)



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


Важно, что тем не менее, конструктор и деструктор производного класса вызываются. Конструктор вызывается потому, что командой "new Derv" все-таки создается объект класса Derv, хоть указатель на него и запоминается в указатель с типом базового класса. Деструктор вызывается потому, что у базового класса деструктор объявлен как виртуальные, и деструктор производного класса его переопределяет.


class Base

{

public:

virtual ~Base() { cout << "Base удален\n"; }

};


class Derv: public Base

{

public:

int *p;


Derv()

{

cout << "Derv - создается массив в куче\n";

p=new int[10];

}


~Derv()

{

cout << "Derv - удаляется массив в куче\n";

delete[] p;

}


void anyMethod()

{

cout << "Derv - anyMethod\n";

}

};


int main()

{

Base *pBase = new Derv;

// pBase->anyMethod(); // Будет ошибка компиляции

delete pBase;

return 0;

}


Так же в этом разделе:
 
MyTetra Share v.0.65
Яндекс индекс цитирования