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

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

  • автор:

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

Допустим есть объект a, какого то типа. Вот этот тип нам и нужно определить, например для создания другого объекта такого же типа. Это звучит конечно немного глупо, так как мы всегда знаем какого типа объект, ну а все таки, например в таком контесте:

. // тут очень много кода, например чужого. . // и у нас есть объект x. // А тут нам нужно создать копию объекта x. tpye(x) a(x); // Например, type это такой волшебный преобразователь. . 

Есть способ вот такой:

templateclass T> void Create(T &x)

Но этот тип T никак не могу вынести за пределы этой функции.

Может я чего то не знаю в современном C++?

Re: как определить тип объекта?

От: LaFlour blog: http://spaces.live.com/laflour
Дата: 26.12.02 06:58
Оценка:

Здравствуйте, comer, Вы писали:

C>Допустим есть объект a, какого то типа. Вот этот тип нам и нужно определить, например для создания другого объекта такого же типа. Это звучит конечно немного глупо, так как мы всегда знаем какого типа объект, ну а все таки, например в таком контесте:

Не пробывал задавать новый тип по полученному
но typeid позволяет определить тип

C>

 int i; cout typeid(i).name; //вывыдет int C>

или может я чтото непонял?

:: Into my SONY MDR-R10 sound «DJ Groove — Ноктюрн» ::
Re: как определить тип объекта?

От: Dima2
Дата: 26.12.02 07:41
Оценка: 8 (1)

Вот смотри здесь немного

Автор: DarkGray
Дата: 12.04.02
Автор: DarkGray
Дата: 14.04.02
Re: как определить тип объекта?

От: jazzer Skype: enerjazzer
Дата: 26.12.02 08:07
Оценка: 4 (1)

Здравствуйте, comer, Вы писали:

C>Допустим есть объект a, какого то типа. Вот этот тип нам и нужно определить, например для создания другого объекта такого же типа. Это звучит конечно немного глупо, так как мы всегда знаем какого типа объект, ну а все таки, например в таком контесте:

C>

C>. // тут очень много кода, например чужого. C>. // и у нас есть объект x. C> // А тут нам нужно создать копию объекта x. C>tpye(x) a(x); // Например, type это такой волшебный преобразователь. C>. C>

см. ниже.

C>Есть способ вот такой:

C>

C>templateclass T> void Create(T &x) < T a(x); >C>

C>Но этот тип T никак не могу вынести за пределы этой функции.

Это невозможно, ибо вызов функции — это выражение, а оно по грамматике не может стоять на месте типа в объявлении.

C>Может я чего то не знаю в современном C++? .

Такого способа, к сожалению, нет, но, возможно, он появится, по крайней мере, Строуструп за это ратует (и я лично это очень поддерживаю), можете посмотреть на ео страничке.

jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got If you always do what you always did

Re: как определить тип объекта?

От: orangy http://twitter.com/orangy
Дата: 26.12.02 11:48
Оценка:

Здравствуйте, comer, Вы писали:

C>Допустим есть объект a, какого то типа. Вот этот тип нам и нужно определить, например для создания другого объекта такого же типа.
Лучше используй парадигму создание-по-прототипу.

class IPrototype < public: virtual IPrototype *Create() = 0; >; class A : public IPrototype < public: A(int b) < . >virtual IPrototype *Create() < return new A(10); > >;

«Develop with pleasure!»
Re[2]: как определить тип объекта?

От: comer http://getboost.codeplex.com/
Дата: 26.12.02 12:15
Оценка:

Здравствуйте, Dima2, Вы писали:

D>http://www.rsdn.ru/Forum/Message.aspx?mid=44873
Автор: DarkGray
Дата: 12.04.02

Да, спасибо, вот здесь как раз и нашел ответ Павла Кузнецова, что в GCC есть __typeof. Мне как раз для GCC. Пока подобной вещи нет в стандарте. Сегодня попробую.

Re[2]: как определить тип объекта?

От: comer http://getboost.codeplex.com/
Дата: 26.12.02 12:18
Оценка:

Здравствуйте, jazzer, Вы писали:

J>Такого способа, к сожалению, нет, но, возможно, он появится, по крайней мере, Строуструп за это ратует (и я лично
это очень поддерживаю), можете посмотреть на ео страничке.

Я тоже двумя руками за! На этапе компиляции всегда должны быть способы узнать об объекте, типе, функции, все то, что знает о нем компилятор, или почти все . А то не честно как то, компилятор знает, а пользователю — болт. Извините за эмоции.

Re: как определить тип объекта?

От: Кодт
Дата: 26.12.02 13:10
Оценка:

Здравствуйте, comer, Вы писали:

C>Может я чего то не знаю в современном C++?

Посмотри в сторону Александреску и его библиотеки Loki, и его же книги (www.moderncppdesign.com)
Может, чего полезного подчерпнешь

Перекуём баги на фичи!
Re[2]: как определить тип объекта?

От: comer http://getboost.codeplex.com/
Дата: 26.12.02 13:50
Оценка:

Здравствуйте, Кодт, Вы писали:

К>Посмотри в сторону Александреску и его библиотеки Loki, и его же книги (www.moderncppdesign.com)
К>Может, чего полезного подчерпнешь

Там эмуляция typeof вряд ли есть

Re[3]: как определить тип объекта?

От: Кодт
Дата: 26.12.02 14:07
Оценка:

Здравствуйте, comer, Вы писали:

C>Там эмуляция typeof вряд ли есть
То есть

Но, с другой стороны, — а откуда возникла такая задача?
Может, ее по-другому можно решить? Раскрой тайну.

Александреску как раз показывает, что ловкость рук творит чудеса.

Перекуём баги на фичи!
Re[4]: как определить тип объекта?

От: comer http://getboost.codeplex.com/
Дата: 26.12.02 15:55
Оценка:

Здравствуйте, Кодт, Вы писали:

C>>Там эмуляция typeof вряд ли есть
К>То есть
Без обид, я ведь искал typeof. IMHO, решения нет. Просто в данном случае loki вряд ли поможет.

К>Но, с другой стороны, — а откуда возникла такая задача?
К>Может, ее по-другому можно решить? Раскрой тайну.
Всегда можно решить по другому, я и решаю именно так.
Понятное дело, что тип мы знаем, что где то выше этот объект описан.
Но ты иногда изменял у какого нибудь объекта a тип vector, например на list, или еще на что нибудь подобное?
А потом бегать по все программе, и заменять vector::iterator на list::iterator.

Конечно, можно было бы определить typedef для данного конкретного объекта a, или все алгоритмы работающие с a описывать в виде шаблонных функция. Но если бы был typeof(), можно было бы решать элегантнее.

Так же как и вообще без шаблонов когда то писали, и ничего, пользовались макросами, и т.п.

Узнать реальный тип объекта

Предположим, есть тип базовый класс SceneObject и есть производные от него классы. Я хочу хранить массив объектов этого класса, для этого завожу vector < SceneObject*>obj. Добавляю туда некоторые объекты производных классов. А когда достаю их оттуда, я хочу узнать их реальный тип. typeid(obj[i]).name() всегда выдает тип SceneObject*. Как узнать реальный тип объекта?( Или может быть, я все делаю неправильно. Как тогда сделать массив объектов, производных от одного класса, чтобы потом можно было определить какой это объект?

Отслеживать
задан 15 мая 2016 в 9:56
195 1 1 серебряный знак 9 9 бронзовых знаков

3 ответа 3

Сортировка: Сброс на вариант по умолчанию

Информация о типе — это дополнительная информация. Когда у вас есть виртуальные функции — есть и их таблица, которая по сути и есть информацией о конкретном типе.

Без этого надо хранить информацию о типе где-то отдельно.

Но как вы хотите использовать эту информацию? Для чего? Обычно — без виртуальных функций — она попросту бессмысленна.

Кстати, раз уж вы пользуетесь указателями и иерархией классов — то учтите, что с точки зрения безопасности деструктор базового класса должен быть объявлен как виртуальный!

Отслеживать
ответ дан 15 мая 2016 в 10:13
218k 15 15 золотых знаков 117 117 серебряных знаков 229 229 бронзовых знаков

Для определения реального типа объекта вы можете воспользоваться dynamic_cast : TYPE* dynamic_cast (object);

Отслеживать
ответ дан 15 мая 2016 в 10:00
Мстислав Павлов Мстислав Павлов
6,757 2 2 золотых знака 18 18 серебряных знаков 40 40 бронзовых знаков

Для классов, не содержащих виртуальные функции, это не работает( Может быть, можно как-то по-другому?

15 мая 2016 в 10:07
а тут разве не нужно знать к чему кастовать? а вопросе вроде обратный вопрос?
15 мая 2016 в 10:08

Да, тут нужно знать( Но можно сделать иерархию if-else и попробовать поприводить ко всему, при некотором желании(хотя это медленно и неоптимально)

15 мая 2016 в 10:11

Очевидно, что Вы неправильно выводите имя, должно быть так: typeid(*obj[i]).name() , но это будет работать лишь в том случае, когда SceneObject является полиморфным, т.е. содержит хотя бы одну виртуальную функцию. Это требуется потому, что без этого RTTI по классу отсутствует, и оператору typeid просто неоткуда узнать, что же за тип ему реально передан.

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

Что касается правильно/не правильно. Обычно, если появляется задача узнать реальный тип данных, то это на 99% ошибка дизайна. Реальный тип практически никогда знать не нужно, для выполнения конкретной реализации существует полиморфное поведение, то есть виртуальные функции.

Типы данных: [[Class]], instanceof и утки

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

Более новая информация по этой теме находится на странице https://learn.javascript.ru/instanceof.

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

Для реализации такой возможности нужен способ определить тип переменной.

Оператор typeof

Мы уже знакомы с простейшим способом – оператором typeof.

Оператор typeof надёжно работает с примитивными типами, кроме null , а также с функциями. Он возвращает для них тип в виде строки:

alert( typeof 1 ); // 'number' alert( typeof true ); // 'boolean' alert( typeof "Текст" ); // 'string' alert( typeof undefined ); // 'undefined' alert( typeof null ); // 'object' (ошибка в языке) alert( typeof alert ); // 'function'

…Но все объекты, включая массивы и даты для typeof – на одно лицо, они имеют один тип ‘object’ :

alert( typeof <> ); // 'object' alert( typeof [] ); // 'object' alert( typeof new Date ); // 'object'

Поэтому различить их при помощи typeof нельзя, и в этом его основной недостаток.

Секретное свойство [[Class]]

Для встроенных объектов есть одна «секретная» возможность узнать их тип, которая связана с методом toString .

Во всех встроенных объектах есть специальное свойство [[Class]] , в котором хранится информация о его типе или конструкторе.

Оно взято в квадратные скобки, так как это свойство – внутреннее. Явно получить его нельзя, но можно прочитать его «в обход», воспользовавшись методом toString стандартного объекта Object .

Его внутренняя реализация выводит [[Class]] в небольшом обрамлении, как «[object значение]» .

var toString = <>.toString; var arr = [1, 2]; alert( toString.call(arr) ); // [object Array] var date = new Date; alert( toString.call(date) ); // [object Date] var user = < name: "Вася" >; alert( toString.call(user) ); // [object Object]

В первой строке мы взяли метод toString , принадлежащий именно стандартному объекту <> . Нам пришлось это сделать, так как у Date и Array – свои собственные методы toString , которые работают иначе.

Затем мы вызываем этот toString в контексте нужного объекта obj , и он возвращает его внутреннее, невидимое другими способами, свойство [[Class]] .

Для получения [[Class]] нужна именно внутренняя реализация toString стандартного объекта Object , другая не подойдёт.

К счастью, методы в JavaScript – это всего лишь функции-свойства объекта, которые можно скопировать в переменную и применить на другом объекте через call/apply . Что мы и делаем для <>.toString .

Метод также можно использовать с примитивами:

alert( <>.toString.call(123) ); // [object Number] alert( <>.toString.call("строка") ); // [object String]

Вызов <>.toString в консоли может выдать ошибку

При тестировании кода в консоли вы можете обнаружить, что если ввести в командную строку <>.toString.call(. ) – будет ошибка. С другой стороны, вызов alert( <>.toString. ) – работает.

Эта ошибка возникает потому, что фигурные скобки < >в основном потоке кода интерпретируются как блок. Интерпретатор читает <>.toString.call(. ) так:

 < >// пустой блок кода .toString.call(. ) // а что это за точка в начале? не понимаю, ошибка!

Фигурные скобки считаются объектом, только если они находятся в контексте выражения. В частности, оборачивание в скобки ( <>.toString. ) тоже сработает нормально.

Для большего удобства можно сделать функцию getClass , которая будет возвращать только сам [[Class]] :

function getClass(obj) < return <>.toString.call(obj).slice(8, -1); > alert( getClass(new Date) ); // Date alert( getClass([1, 2, 3]) ); // Array

Заметим, что свойство [[Class]] есть и доступно для чтения указанным способом – у всех встроенных объектов. Но его нет у объектов, которые создают наши функции. Точнее, оно есть, но равно всегда «Object» .

function User() <> var user = new User(); alert( <>.toString.call(user) ); // [object Object], не [object User]

Поэтому узнать тип таким образом можно только для встроенных объектов.

Метод Array.isArray()

Для проверки типа на массив есть специальный метод: Array.isArray(arr) . Он возвращает true только если arr – массив:

alert( Array.isArray([1,2,3]) ); // true alert( Array.isArray("not array")); // false

Но этот метод – единственный в своём роде.

Других аналогичных, типа Object.isObject , Date.isDate – нет.

Оператор instanceof

Оператор instanceof позволяет проверить, создан ли объект данной функцией, причём работает для любых функций – как встроенных, так и наших.

function User() <> var user = new User(); alert( user instanceof User ); // true

Таким образом, instanceof , в отличие от [[Class]] и typeof может помочь выяснить тип для новых объектов, созданных нашими конструкторами.

Заметим, что оператор instanceof – сложнее, чем кажется. Он учитывает наследование, которое мы пока не проходили, но скоро изучим и затем вернёмся к instanceof в главе Проверка класса: «instanceof».

Утиная типизация

Альтернативный подход к типу – «утиная типизация», которая основана на одной известной пословице: «If it looks like a duck, swims like a duck and quacks like a duck, then it probably is a duck (who cares what it really is)».

В переводе: «Если это выглядит как утка, плавает как утка и крякает как утка, то, вероятно, это утка (какая разница, что это на самом деле)».

Смысл утиной типизации – в проверке необходимых методов и свойств.

Например, мы можем проверить, что объект – массив, не вызывая Array.isArray , а просто уточнив наличие важного для нас метода, например splice :

var something = [1, 2, 3]; if (something.splice)

Обратите внимание – в if мы не вызываем метод something.splice() , а пробуем получить само свойство something.splice . Для массивов оно всегда есть и является функцией, т.е. даст в логическом контексте true .

Проверить на дату можно, определив наличие метода getTime :

var x = new Date(); if (x.getTime) < alert( 'Дата!' ); alert( x.getTime() ); // работаем с датой >

С виду такая проверка хрупка, её можно «сломать», передав похожий объект с тем же методом.

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

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

Проверка интерфейса

Если говорить словами «классического программирования», то «duck typing» – это проверка реализации объектом требуемого интерфейса. Если реализует – ок, используем его. Если нет – значит это что-то другое.

Пример полиморфной функции

Пример полиморфной функции – sayHi(who) , которая будет говорить «Привет» своему аргументу, причём если передан массив – то «Привет» каждому:

function sayHi(who) < if (Array.isArray(who)) < who.forEach(sayHi); >else < alert( 'Привет, ' + who ); >> // Вызов с примитивным аргументом sayHi("Вася"); // Привет, Вася // Вызов с массивом sayHi(["Саша", "Петя"]); // Привет, Саша. Петя // Вызов с вложенными массивами - тоже работает! sayHi(["Саша", "Петя", ["Маша", "Юля"]]); // Привет Саша..Петя..Маша..Юля

Проверку на массив в этом примере можно заменить на «утиную» – нам ведь нужен только метод forEach :

function sayHi(who) < if (who.forEach) < // если есть forEach who.forEach(sayHi); // предполагаем, что он ведёт себя "как надо" >else < alert( 'Привет, ' + who ); >>

Итого

Для написания полиморфных (это удобно!) функций нам нужна проверка типов.

  • Для примитивов с ней отлично справляется оператор typeof . У него две особенности:
    • Он считает null объектом, это внутренняя ошибка в языке.
    • Для функций он возвращает function , по стандарту функция не считается базовым типом, но на практике это удобно и полезно.

    Задачи

    Полиморфная функция formatDate

    важность: 5

    Напишите функцию formatDate(date) , которая возвращает дату в формате dd.mm.yy .

    Её первый аргумент должен содержать дату в одном из видов:

    1. Как объект Date .
    2. Как строку, например yyyy-mm-dd или другую в стандартном формате даты.
    3. Как число секунд с 01.01.1970 .
    4. Как массив [гггг, мм, дд] , месяц начинается с нуля

    Для этого вам понадобится определить тип данных аргумента и, при необходимости, преобразовать входные данные в нужный формат.

    function formatDate(date) < /* ваш код */ >alert( formatDate('2011-10-02') ); // 02.10.11 alert( formatDate(1234567890) ); // 14.02.09 alert( formatDate([2014, 0, 1]) ); // 01.01.14 alert( formatDate(new Date(2014, 0, 1)) ); // 01.01.14

    Для определения примитивного типа строка/число подойдёт оператор typeof.

    Примеры его работы:

    alert( typeof 123 ); // "number" alert( typeof "строка" ); // "string" alert( typeof new Date() ); // "object" alert( typeof [] ); // "object"

    Оператор typeof не умеет различать разные типы объектов, они для него все на одно лицо: «object» . Поэтому он не сможет отличить Date от Array .

    Для отличия Array используем вызов Array.isArray . Если он неверен, значит у нас дата.

    function formatDate(date) < if (typeof date == 'number') < // перевести секунды в миллисекунды и преобразовать к Date date = new Date(date * 1000); >else if (typeof date == 'string') < // строка в стандартном формате автоматически будет разобрана в дату date = new Date(date); >else if (Array.isArray(date)) < date = new Date(date[0], date[1], date[2]); >// преобразования для поддержки полиморфизма завершены, // теперь мы работаем с датой (форматируем её) return date.toLocaleString("ru", ); /* // можно и вручную, если лень добавлять в старый IE поддержку локализации var day = date.getDate(); if (day < 10) day = '0' + day; var month = date.getMonth() + 1; if (month < 10) month = '0' + month; // взять 2 последние цифры года var year = date.getFullYear() % 100; if (year < 10) year = '0' + year; var formattedDate = day + '.' + month + '.' + year; return formattedDate; */ >

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

    Чтобы узнать класс объекта в Java, можно использовать метод getClass() :

    Object obj = new String("Hello, World!"); Class cls = obj.getClass(); System.out.println("Class of obj: " + cls.getName()); 

    В этом примере мы создаем объект String , затем вызываем метод getClass() , чтобы получить класс этого объекта, и, наконец, используем метод getName() , чтобы получить имя класса. Результатом будет:

    Class of obj: java.lang.String 

    Метод getClass() возвращает объект типа Class , который содержит информацию о классе объекта. Мы можем использовать этот объект для получения информации о классе, такой как имя, модификаторы доступа, поля, методы и т.д.

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

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