Как определить, какой тип к dynamic_cast?

0

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

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

Например, суперкласс может быть Value, а подкласс - RationalNumber.

Мой план состоял в том, чтобы установить идентификатор значения int для RationalNumber, я не знаю, 1, а затем, когда я использую dynamic_cast, он определит, что объект Value* самом деле является RationalNumber, и операция будет выполнена.

Как я могу это реализовать?

  • 0
    Почему вы пытаетесь "реализовать" dynamic_cast ? Это встроено в язык! Вы просто пытаетесь определить, будет ли dynamic_cast успешным или неуспешным? Вы даже уверены, что это необходимо? Когда у вас есть виртуальные интерфейсы, это обычно не нужно.
  • 0
    Я имею в виду, как бы я использовал это? Я передаю указатели суперкласса в методы, и мне нужно определить, на какой тип подкласса ссылается указатель. Я уверен, что это необходимо для того, что я пытаюсь сделать. Несколько подклассов будут получены из одного суперкласса, и выполненная операция будет отличаться в зависимости от того, какой из них хранится в указателе. Это только предотвращает необходимость создания метода для каждой возможной комбинации параметров.
Показать ещё 1 комментарий
Теги:
dynamic-cast

3 ответа

2
Лучший ответ

Типичный пример:

class Value
{
 public:
   virtual ~Value();
};

class RationalNumber : public Value
{
  ... 
}


Value *v = new RationalNumber(...)


... 
RationalNumber* test = dynamic_cast<RationalNumber*>(v);

if (v)
   cout << "v is a rational number" << endl;
else
   cout << "v is a not rational number" << endl;

Обратите внимание, что это НЕ является хорошим решением почти во всех случаях, когда у вас есть наследование. Я пишу компилятор, и это первый раз, когда я когда-либо использовал dynamic_cast - главным образом потому, что есть некоторые довольно общие функции, которые имеют дело с (например) указателями класса ExprAST и добавляют ВСЕ варианты вариантов, которые все производные классы (31 класс в настоящее время) в составе ExprAST были бы весьма непрактичными. (И, конечно, вызов, выполняющий expr->isVariableExprAST(), не намного лучше, чем VariableExprAST* var = dynamic_cast<VariableExprAST*>(expr); if (var)... - это то же количество кода, более или менее).

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

Более подходящим решением является использование виртуальной функции, которая является общей для всех классов, например:

class Value
{
 public:
   virtual ~Value();
   virtual void SomeMethod() = 0;
};

class RationalNumber : public Value
{
  ... 
  virtual void SomeMethod() { ... }
}

class IrrationalNumber : public Value
{
  ... 
  virtual void SomeMethod() { ... }
}


Value *v = ... 

v->SomeMethod();

В этом случае вам не нужно выполнять ЛЮБЫЕ проверки - вам просто нужно реализовать метод SomeMethod для всех подтипов.

  • 0
    В этой программе выполняемая операция зависит от объекта, сохраненного указателем значения. Поэтому, если * v указывает на RationalNumber, а не на IrrationalNumber, произойдет что-то еще. Можно ли обойти это, создав значение идентификатора и сохранив виртуальный метод для проверки идентификатора, и, в зависимости от значения идентификатора, выполните каждый? Например, в этом случае RationalNumber ID = 1. RationalNumber::checkID{ return ID; } if (v->checkID == 1 && w->checkID == 1){ //execute method } else if ... ?
  • 0
    Это похоже на BAD-решение, и я отредактировал свой ответ, чтобы объяснить, как вы обычно решаете эту проблему, когда у вас нет 30 с лишним классов, которые имеют совершенно другой набор функций (например, переменная имеет адрес, но нет адреса цикла for или двоичного выражения.
2

Оператор dynamic_cast определяет тип объекта во время выполнения в соответствии со значением указателя V-таблицы объекта (неявное поле члена, которое добавляется к классу объекта, когда у вас есть одна или несколько виртуальных функций в этом классе).

Здесь нечего реализовать, и вы можете просто называть его. Например:

bool isRationalNumber(Value* object)
{
    RationalNumber* number = dynamic_cast<RationalNumber*>(object);
    if (number == NULL)
        return false;
    return true;
}

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

Кроме того, на некоторых компиляторах вам необходимо включить RTTI в настройках проекта.

И, наконец, небольшое предложение (более личное мнение, поэтому вы можете игнорировать его):

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

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

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

  • 0
    Я не пытаюсь реализовать методы в классах. Существуют отдельные классы, у которых есть методы, которые передают указатели Value и работают в зависимости от того, какой объект хранят указатели Value. Я понимаю, что это отчасти нелогично, но я говорил об этом с несколькими другими людьми, и они посадили семя, и на данный момент это, кажется, лучший способ выполнить то, что ему нужно.
  • 0
    @ user3502205: Могут быть случаи, когда dynamic_cast является лучшей (или единственной) альтернативой. Как я уже сказал, это скорее личное мнение, что вы должны стараться избегать его использования (и проверить свой дизайн, если видите, что у вас нет альтернатив). Некоторые люди будут утверждать против этого мнения, поэтому вы можете игнорировать его. Использовать сам оператор довольно просто, как показано в ответе выше.
0

Стандартный способ - dynamic_cast объект к производному классу, а затем проверить, является ли результат null или нет. Например (используя вашу терминологию):

void method(SuperClass* object) {

  SubClass* subclass = dynamic_cast<SubClass*>(object);

  if (subclass) {
    // the object is a 'SubClass'
    // do stuff...
  }

}

Если у вас есть несколько подклассов, вам придется проверять их отдельно. Например:

void method(SuperClass* object) {

  SubClass_1* subclass_1 = dynamic_cast<SubClass_1*>(object);
  if (subclass_1) {
    // the object is a 'SubClass_1'
    // do stuff...
    return;
  }

  SubClass_2* subclass_2 = dynamic_cast<SubClass_2*>(object);
  if (subclass_2) {
    // the object is a 'SubClass_2'
    // do stuff...
    return;
  }


}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню