Как узнать класс объекта с
Перейти к содержимому

Как узнать класс объекта с

Как узнать класс объекта с

Все классы в .NET, даже те, которые мы сами создаем, а также базовые типы, такие как System.Int32 , являются неявно производными от класса Object. Даже если мы не указываем класс Object в качестве базового, по умолчанию неявно класс Object все равно стоит на вершине иерархии наследования. Поэтому все типы и классы могут реализовать те методы, которые определены в классе System.Object. Рассмотрим эти методы.

ToString

Метод ToString служит для получения строкового представления данного объекта. Для базовых типов просто будет выводиться их строковое значение:

Для классов же этот метод выводит полное название класса с указанием пространства имен, в котором определен этот класс. И мы можем переопределить данный метод. Посмотрим на примере:

Для переопределения метода ToString() в классе Clock, который представляет часы, используется ключевое слово override (как и при обычном переопределении виртуальных или абстрактных методов). В данном случае метод ToString() выводит в строке значения свойств Hours, Minutes, Seconds.

Класс Person не переопределяет метод ToString, поэтому для этого класса срабатывает стандартная реализация этого метода, которая выводит просто название класса.

Кстати в данном случае мы могли задействовать обе реализации:

То есть если имя — свойство Name не имеет значения, оно представляет пустую строку, то возвращается базовая реализация — название класса. Стоит отметить, что базовая реализация возвращает не просто строку, а объект string? — то есть это может быть строка string, либо значение null , которое указывает на отсутствие значения. И в реальности в качестве возвращаемого типа для метода мы можем использовать как string , так и string?

Если же имя у объекта Person установлено, то возвращается значение свойства Name. Для проверки строки на наличие значения применяется метод String.IsNullOrEmpty() .

Стоит отметить, что различные технологии на платформе .NET активно используют метод ToString для разных целей. В частности, тот же метод Console.WriteLine() по умолчанию выводит именно строковое представление объекта. Поэтому, если нам надо вывести строковое представление объекта на консоль, то при передаче объекта в метод Console.WriteLine необязательно использовать метод ToString() — он вызывается неявно:

Метод GetHashCode

Метод GetHashCode позволяет возвратить некоторое числовое значение, которое будет соответствовать данному объекту или его хэш-код. По данному числу, например, можно сравнивать объекты. Можно определять самые разные алгоритмы генерации подобного числа или взять реализаци базового типа:

В данном случае метод GetHashCode возвращает хеш-код для значения свойства Name. То есть два объекта Person, которые имеют одно и то же имя, будут возвращать один и тот же хеш-код. Однако в реальности алгоритм может быть самым различным.

Получение типа объекта и метод GetType

Метод GetType позволяет получить тип данного объекта:

Этот метод возвращает объект Type , то есть тип объекта.

С помощью ключевого слова typeof мы получаем тип класса и сравниваем его с типом объекта. И если этот объект представляет тип Client, то выполняем определенные действия.

Причем поскольку класс Object является базовым типом для всех классов, то мы можем переменной типа object присвоить объект любого типа. Однако для этой переменной метод GetType все равно вернет тот тип, на объект которого ссылается переменная. То есть в данном случае объект типа Person.

Стоит отметить, что проверку типа можно скоратить с помощью оператора is :

В отличие от методов ToString, Equals, GetHashCode метод GetType() не переопределяется.

Метод Equals

Метод Equals позволяет сравнить два объекта на равенство. В качестве параметра он принимает объект для сравнения в виде типа object и возврашает true , если оба объекта равны:

Например, реализуем данный метод в классе Person:

Метод Equals принимает в качестве параметра объект любого типа, который мы затем приводим к текущему классу — классу Person.

Если переданный объект представляет тип Person, то возвращаем результат сравнения имен двух объектов Person. Если же объект представляет другой тип, то возвращается false.

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

Стоит отметить, что вместе с методом Equals следует реализовать метод GetHashCode.

И если следует сравнивать два сложных объекта, как в данном случае, то лучше использовать метод Equals, а не стандартную операцию ==.

Как проверить, является ли тип объекта определенным подклассом в C++?

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

Я предполагаю, что у вас есть такая ситуация:

Если это то, что у вас есть, то попробуйте сделать что-то вроде этого:

Edit: С момента дебатов об этом ответе все еще продолжается после стольких лет, я подумал, что должен добавить некоторые рекомендации. Если у вас есть указатель или ссылка на базовый класс, и ваш код должен знать производного класса объекта, то он нарушает принцип подстановки Лисков. Дядя Боб называет это «анафема объектно-ориентированного дизайна».

вы можете сделать это с помощью dynamic_cast (по крайней мере для полиморфных типов).

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

dynamic_cast можно определить, содержит ли тип целевой тип в любом месте иерархии наследования (да, это малоизвестная функция, которая, если B наследует от A и C , он может превратить A* непосредственно в C* ). typeid() можно определить точный тип объекта. Однако, они должны использоваться очень экономно. Как уже упоминалось, вы всегда должны избегать динамической идентификации типов, потому что это указывает на недостаток дизайна. (также, если вы знайте, что объект уверен в целевом типе, вы можете сделать downcast с static_cast . Boost предлагает polymorphic_downcast это сделает уныние с dynamic_cast и assert в режиме отладки и в режиме релиза он будет просто использовать static_cast ).

Я не согласен с тем, что вы никогда не должны проверять тип объекта в C++. Если вы можете избежать этого, я согласен, что вы должны. Однако говорить, что вы никогда не должны этого делать ни при каких обстоятельствах, слишком далеко. Вы можете сделать это на многих языках, и это может сделать вашу жизнь намного проще. Говард Пинсли, например, показал нам, как в своем посте на C#.

Я много работаю с Qt Framework. В общем, я моделирую то, что я делаю после того, как они делают вещи (по крайней мере, когда работа в их рамках). Класс QObject является базовым классом всех объектов Qt. Этот класс имеет функции isWidgetType() и isWindowType () в качестве быстрой проверки подкласса. Так почему бы не проверить свои собственные производные классы, которые сопоставимы по своей природе? Вот QObject спина от некоторых из этих других сообщений:

и затем, когда вы передаете указатель на QObject, вы можете проверить, указывает ли он на ваш производный класс, вызвав статический член функция:

я не знаю, правильно ли я понимаю вашу проблему, поэтому позвольте мне повторить ее своими словами.

проблема: учитывая классы B и D , определить D является наследником B (или наоборот?)

решение: используйте магию шаблонов! Хорошо, серьезно, вам нужно взглянуть на LOKI, отличную библиотеку метапрограммирования шаблонов, созданную легендарным автором c++ Андреем Александреску.

более конкретно, скачать Локи и включить заголовок TypeManip.h из него в исходном коде затем используйте SuperSubclass шаблон класса следующим образом:

согласно документации, SuperSubClass<B,D>::value будет true, если B открытая база D , или B и D являются псевдонимами одного типа.

либо D является наследником B или D это то же самое, что B .

я надеюсь, что это помогает.

edit:

Пожалуйста, обратите внимание на оценку SuperSubClass<B,D>::value происходит во время компиляции, в отличие от некоторых методов, которые используют dynamic_cast , следовательно, нет штрафа за использование этой системы во время выполнения.

Как узнать тип объекта, на который указывает указатель в C ++?

Предположим, я определил два класса на основе одного базового класса:

Тогда теперь есть класс с именем Collect, который содержит указатель на Basic учебный класс

В этом классе функция run() был определен, который будет выполнять некоторые операции в зависимости от типа объекта, на который указывает указатель:

Тогда мой вопрос заключается в следующем:

  • С C ++ возможно ли узнать тип объекта, на который указывает указатель?
  • Является ли хорошей практикой выполнение чего-то другого в зависимости от типа объекта, на который указывает указатель, как показано на рисунке run функционировать?

Решение

Чтобы выполнить такую ​​проверку, ваш базовый класс Basic должен иметь хотя бы одного виртуального члена. Поскольку вы хотите построить иерархию классов, я бы хотел сделать

Basic виртуальный, чтобы убедиться, что это будет правильно удален в то же время.

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

Теперь вы можете написать свой чек:

dynamic_cast вернет nullptr если это не удастся, так что вы будете входить только в тело if когда ваш бросок удался и pDerived содержит действительный указатель на правый производный объект.

Другие решения

В С ++ мы обычно используем База класс, а не базовый класс.

В любом случае, в общем, если ваш базовый класс полиморфен (содержит виртуальные функции), вы можете использовать dynamic_cast:

Это означает, что объект «a» имеет «static-type»: Base; и «динамический тип»: производный.

Если в вашем базовом классе нет виртуальных функций, указатель вашего указателя всегда будет иметь тип Basic и иметь поведение объекта типа Basic , На самом деле, даже с виртуальной функцией, указатель типа Basic* всегда указывает на объект типа Basic , Но «динамический тип» у pointee может быть другим.

Если ваш базовый класс имеет хотя бы одну виртуальную функцию, то вы можете положиться на Информация о типе времени выполнения : ты можешь использовать dynamic_cast или же typeid чтобы получить динамический тип pointee.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *