требуется при использовании переменной-члена static
.
В главном файле OneStatic
, и каждый раз конструктор по умолчанию OneStatic
инкрементирует статическую переменную. В результате вывод main
из
3
3
3
Каждый вызов getCount
возвращает одно и то же целое значение, даже несмотря на то, что он делается для различных экземпляров класса.
8.6. Определение типа объекта во время выполнения
Во время выполнения требуется динамически узнавать тип определенного класса.
Для запроса, на объект какого типа указывает адрес объекта, используйте идентификацию типов во время выполнения (обычно называемую просто RTTI — runtime type identification). Пример 8.6 показывает, как это делается.
#include <iostream>
#include <typeinfo>
using namespace std;
class Base {};
class Derived : public Base {};
int main() {
Base b, bb;
Derived d;
// Используем typeid для проверки равенства типов
if (typeid(b) == typeid(d)) { // No
cout << 'b и d имеют один и тот же тип.
';
}
if (typeid(b) == typeid(bb)) { // Yes
cout << 'b и bb имеют один и тот же тип.
';
}
it (typeid(a) == typeid(Derived)) { // Yes
cout << 'd имеет тип Derived.
';
}
}
Пример 8.6 показывает, как использовать оператор typeid
для определения и сравнения типов объектов, typeid
принимает выражение или тип и возвращает ссылку на объект типа type_info
или его подкласс (что зависит от реализации). Возвращенное значение можно использовать для проверки на равенство или получить строковое представление имени типа. Например, сравнить типы двух объектов можно так.
if (typeid(b) == typeid(d)) {
Это выражение возвращает истину, если возвращаемые объекты type_info
равны. Это работает благодаря тому, что typeid
возвращает ссылку на статический объект, так что при его вызове для двух объектов одного и того же типа будут получены две ссылки на один и тот же объект и сравнение вернет истину.
typeid
также можно использовать непосредственно с типом, как здесь.
if (typeid(d) == typeid(Derived)) {
Это позволяет явно проверять определенный тип.
Вероятно, наиболее часто typeid
используется для отладки. Для записи имени типа используйте type_info::name
, как здесь.
std::cout << typeid(d).name() << std::endl;
При передаче объектов различных типов это может быть очень полезно. Строка, завершающаяся нулем, возвращаемая name
, зависит от реализации, но вы можете ожидать (но не полагаться на это), что она будет равна имени типа. Это также работает и для встроенных типов.
Не злоупотребляйте этой методикой, основывая на информации о типе логику программы, если это не абсолютно необходимо. В общем случае наличие логики, которая выполняет что-то похожее на следующее, расценивается как плохой дизайн.
Если obj
имеет тип X
, сделать что-то одно, а если obj
имеет тип Y
, сделать что-то другое.
Это плохой дизайн, потому что клиентский код теперь содержит избыточные зависимости от типов используемых объектов. Это также приводит к большой каше из if/then кода, который то и дело повторяется, если для объектов типов X
или Y
требуется различное поведение. Объектно-ориентированное программирование и полиморфизм существуют в большой степени для того, чтобы избавить нас от написания подобного рода логики. Если для какого-либо семейства связанных классов требуется зависящее от типа поведение, то они все должны наследоваться от какого-то базового класса и использовать виртуальные функции, динамически вызывая различное поведение в зависимости от типа.
RTTI приводит к накладным расходам, так что компиляторы обычно по умолчанию его отключают. Скорее всего ваш компилятор имеет параметр командной строки для включения RTTI. Также это не единственный способ, которым можно получить информацию о типе. Другая методика приведена в рецепте 8.7.
Рецепт 8.7.
8.7. Определение, является ли класс объекта подклассом другого класса
Имеется два объекта и требуется узнать, имеют ли их классы отношения на уровне базовый класс/производный класс, или они не связаны друг с другом.
Используйте оператор dynamic_cast
, который пытается выполнить преобразование одного типа в другой. Результат скажет, имеется ли связь между классами. Пример 8.7 представляет код, который это делает.