C++ RTTI жизнеспособные [закрытые] примеры

Исключение нулевого указателя - это индикатор того, что вы используете объект, не инициализируя его.

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

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

Приведенный ниже код дает вам исключение с нулевым указателем.

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}

Поскольку вы используете Obj_Student, но вы забыли инициализировать его, как в правильном коде, показанном ниже:

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student = new Student();
            obj_Student.setId(12);
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}
29
задан Bill the Lizard 8 August 2012 в 01:54
поделиться

10 ответов

Нециклический Посетитель (PDF) является большим использованием его.

8
ответ дан fizzer 28 November 2019 в 01:56
поделиться

Можно использовать RTTI с dynamic_cast для получения указателя на производный класс для использования его для вызова быстрого, введите специализированный алгоритм. И вместо того, чтобы использовать виртуальные методы через базовый класс, это выполнит прямые и встроенные вызовы.

Это ускорило вещи для меня большое использование GCC. Visual Studio, казалось, не сделала также, она может иметь более медленный dynamic_cast поиск.

Пример:

D* obj = dynamic_cast<D*>(base);
if (obj) {
    for(unsigned i=0; i<1000; ++i)
        f(obj->D::key(i));
    }
} else {
    for(unsigned i=0; i<1000; ++i)
        f(base->key(i));
    }
}
6
ответ дан Zan Lynx 28 November 2019 в 01:56
поделиться

Как насчет boost :: any object!

Это в основном использует информацию RTTI для хранения любого объекта и извлечения этого объекта с использованием boost :: any_cast <>.

8
ответ дан Martin York 28 November 2019 в 01:56
поделиться

Не могу сказать, что когда-либо нашел применение для in в реальной жизни, но RTTI упоминается в Effective C ++ как возможное решение для нескольких методов в C ++. Это связано с тем, что диспетчеризация метода выполняется для динамического типа параметра this, но для статического типа аргументов.

class base
{
  void foo(base *b) = 0; // dynamic on the parameter type as well
};

class B : public base {...}
class B1 : public B {...}
class B2 : public B {...}

class A : public base
{
  void foo(base *b)
  {
    if (B1 *b1=dynamic_cast<B1*>(b))
      doFoo(b1);
    else if (B2 *b2=dynamic_cast<B2*>(b))
      doFoo(b2);
  }
};
5
ответ дан 1800 INFORMATION 28 November 2019 в 01:56
поделиться

Я работал над моделированием самолета однажды, которое имело что они (несколько смутно) называемый "Базой данных Моделирования". Вы могли регистровые переменные как плавания или ints или строки в нем, и люди могли искать их по имени и вытащить ссылку на них. Вы могли также зарегистрировать модель (объект класса убывал от "SimModel"). Путем я использовал RTTI, должен был сделать его так, Вы могли искать модели, которые реализуют данный интерфейс:

SimModel* SimDatabase::FindModel<type*>(char* name="")
{
   foreach(SimModel* mo in ModelList)
   if(name == "" || mo->name eq name)
   {
       if(dynamic_cast<type*>mo != NULL)
       {
           return dynamic_cast<type*>mo;
       }
   }
   return NULL;
}

базовый класс SimModel:

class public SimModel
{
    public:
        void RunModel()=0;
};

интерфейс в качестве примера мог бы быть "EngineModel":

class EngineModelInterface : public SimModel
{
    public:
        float RPM()=0;
        float FuelFlow()=0;
        void SetThrottle(float setting)=0; 
};

Теперь, для создания механизма Lycoming и Continental:

class LycomingIO540 : public EngineModelInterface 
{
    public:
        float RPM()
        {
            return rpm;
        }
        float FuelFlow()
        {
            return throttleSetting * 10.0;
        }
        void SetThrottle(float setting) 
        {
            throttleSetting = setting
        }
        void RunModel() // from SimModel base class
        {
            if(throttleSetting > 0.5)
                rpm += 1;
            else
                rpm -= 1;
        }
    private:
        float rpm, throttleSetting;
};
class Continental350: public EngineModelInterface 
{
    public:
        float RPM()
        {
            return rand();
        }
        float FuelFlow()
        {
            return rand;
        }
        void SetThrottle(float setting) 
        {
        }
        void RunModel() // from SimModel base class
        {
        }
};

Теперь, вот некоторый код, где кто-то хочет механизм:

.
.
EngineModelInterface * eng = simDB.FindModel<EngineModelInterface *>();
.
.
fuel = fuel - deltaTime * eng->FuelFlow();    
.
.
.

Код довольно псевдо, но я надеюсь, что он объясняет идею. Один разработчик может записать код, который зависит от наличия Механизма, но, пока это имеет что-то, что реализует интерфейс механизма, это не заботится, каково это. Таким образом, код, который обновляет количество топлива в корпусах, полностью разъединяется от всего кроме FindModel<> () функция и чистый виртуальный интерфейс EngineModel, что он интересуется использованием. Кто-то год спустя может сделать новую модель механизма, зарегистрировать ее в SimulationDatabase и парне выше того, который обновляет топливо, начнет использовать его автоматически. Я на самом деле сделал его так, Вы могли загрузить новые модели как плагины (DLLs) во времени выполнения, и как только они регистрируются в SimulationDatabase, они могли быть найдены с FindModel<> (), даже при том, что код, который искал их, был скомпилирован и встроен в DLL за месяцы до того, как новый DLL существовал. Вы могли также добавить новые Интерфейсы, которые происходят из SimModel с чем-то, что реализует их в одном DLL, что-то, что ищет их в другом DLL, и как только Вы загружаете обоих DLLs, можно сделать FindModel<> () для вкладывания модели другой. Даже при том, что сам Интерфейс даже не существовал, когда главное приложение было создано.

, Между прочим, RTTI не всегда работает через границы DLL. Так как я использовал QT так или иначе, я использовал qobject_cast вместо dynamic_cast. Каждый класс должен был наследоваться QObject (и получить moc'd), но qobject метаданные были всегда доступны. Если Вы не будете заботиться о DLLs, или Вы используете набор инструментальных средств, где RTTI делает работа через границы DLL (сравнения типов на основе сравнений строк вместо хешей или безотносительно), то все вышеупомянутое с dynamic_cast будет работать просто великолепно.

3
ответ дан KeyserSoze 28 November 2019 в 01:56
поделиться

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

Это только один пример того, где RTTI может быть полезен; возможно, это не самый элегантный способ решения проблемы, но использование RTTI делает приложение более устойчивым при использовании этого шаблона.

3
ответ дан Nick 28 November 2019 в 01:56
поделиться

Иногда static_cast и броски C-стиля просто не достаточно, и Вам нужно dynamic_cast, пример этого - когда у Вас есть страшное иерархия ромбовидной формы (изображение из Википедии).

diamond inheritance

struct top {
};

struct left : top { 
    int i;
    left() : i(42) {}
};

struct right : top {
    std::string name;
    right() : name("plonk") { }
};

struct bottom : left, right {
};

bottom b;
left* p = &b;

//right* r = static_cast<right*>(p); // Compilation error!
//right* r = (right*)p;              // Gives bad pointer silently 
right* r = dynamic_cast<right*>(p);  // OK
2
ответ дан Community 28 November 2019 в 01:56
поделиться

Я использовал RTTI, когда делал несколько работ на холсте с Qt несколько лет назад. Было чертовски удобно, когда выполняли тесты на попадание на объекты, использовать RTTI, чтобы определить, что я собираюсь делать с формой, которую я «ударил». Но я не использовал это иначе в рабочем коде.

0
ответ дан itsmatt 28 November 2019 в 01:56
поделиться

Я использую его с Динамическая Двойная Отправка и Шаблоны . В основном это дает способность наблюдать/слушать только интересные части объекта.

0
ответ дан Johann Gerell 28 November 2019 в 01:56
поделиться

Примеры использования, которые у меня есть в моих проектах (если вы знаете какое-либо лучшее решение для конкретных случаев, прокомментируйте):

  1. То же, что уже упоминалось в 1800 ИНФОРМАЦИЯ:

    Вы ' Мне потребуется dynamic_cast для реализации operator == или operator < для производных классов. По крайней мере, я не знаю другого пути.

  2. Если вы хотите реализовать что-то вроде boost :: any или другой вариант контейнера.

  3. В одной игре в классе Client , который имел std :: set (возможные экземпляры: NetPlayer и LocalPlayer ) (у которого может быть не более одного LocalPlayer ), мне нужна была функция LocalPlayer * Client :: localPlayer () . Эта функция используется очень редко, поэтому я хотел избежать загромождения Клиента дополнительной локальной переменной-членом и всем дополнительным кодом для ее обработки.

  4. У меня есть абстрактный класс Variable с несколькими реализациями. Все зарегистрированные переменные находятся в некоторых std :: set vars .И есть несколько встроенных переменных типа BuiltinVar , которые сохраняются во встроенных модулях std :: vector . В некоторых случаях у меня есть переменная * , и мне нужно проверить, является ли она BuiltinVar * и внутри встроенных . Я мог бы сделать это либо с помощью некоторой проверки диапазона памяти, либо с помощью dynamic_cast (в любом случае я могу быть уверен, что все экземпляры BuiltinVar находятся в этом векторе).

  5. У меня есть сетка из GameObject s, и мне нужно проверить, есть ли объект Player (специализированный GameObject ) внутри одной сетки. У меня могла бы быть функция bool GameObject :: isPlayer () , которая всегда возвращает false, кроме Player , или я мог бы использовать RTTI. Есть еще много подобных примеров, когда люди часто реализуют такие функции, как Object :: isOfTypeXY () , и из-за этого базовый класс становится очень загроможденным.

    Это также иногда относится к другим очень специальным функциям, таким как Object :: checkScore_doThisActionOnlyIfIAmAPlayer () . Есть некоторый здравый смысл, необходимый, чтобы решить, когда действительно имеет смысл иметь такую ​​функцию в базовом классе, а когда нет.

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

  7. Иногда мне нужно сохранить указатель некоторых данных в каком-либо поле данных какой-либо библиотеки C (например, SDL или что-то еще), и я получаю его позже в другом месте или в качестве обратного вызова. Я провожу здесь dynamic_cast , чтобы убедиться, что получаю то, что ожидаю.

  8. У меня есть класс TaskManager , который выполняет некоторую очередь из Task s. Для некоторых Задач , когда я добавляю их в список, я хочу удалить из очереди другие Задачи того же типа.

1
ответ дан 28 November 2019 в 01:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: