Безопасный способ динамического приведения типа к типу?

1) Установка первой панели:

JFrame frame=new JFrame();
frame.getContentPane().add(new JPanel());

2) Замена панели:

frame.getContentPane().removeAll();
frame.getContentPane().add(new JPanel());

Также обратите внимание, что вы должны сделать это в потоке события, чтобы обеспечить это использует SwingUtilities.invokeLater или SwingWorker

1
задан QuickQuestion 5 March 2019 в 15:40
поделиться

4 ответа

Если вы используете приведение в стиле C для преобразования в Alpha*, аналогично static_cast перед использованием динамического приведения, то динамическое приведение не дает никакого эффекта. здесь ваш код выполняется, потому что оба класса имеют одинаковый интерфейс, но в действительности это неопределенное поведение.

Обычно вы хотите использовать динамическое приведение к восходящему / нисходящему из / в базовый класс в / из его производного класса.

Например, если мы добавим базовый интерфейс, затем преобразуем указатель void * в этот базовый класс, а затем используем динамическое приведение, чтобы выполнить преобразование, код работает как положено и печатается только один раз. ]

#include <stdio.h>

class Speaker {
public:
  virtual void Speak() = 0;
};

class Alpha: public Speaker {
public:
  virtual void Speak() { printf("A"); }
};

class Beta: public Speaker {
public:
  virtual void Speak() { printf("B"); }
};

int main(){
  void *p = new Alpha;
  // Convert to base type, using static_cast                                    
  Speaker *s = static_cast<Speaker *>(p);
  // Attempt Upcasts                                                            
  Alpha*a = dynamic_cast<Alpha*>(s);
  Beta*b = dynamic_cast<Beta*>(s);

  // See if it worked                                                           
  if (a)
    a->Speak();
  if (b)
    b->Speak();
  return 0;
}

Выходы: A

0
ответ дан Tezirg 5 March 2019 в 15:40
поделиться

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

Учитывая, что указатель void был преобразован из Alpha*, вы можете преобразовать его обратно, используя статическое приведение:

auto a_ptr = static_cast<Alpha*>(p);

Затем вы можете использовать dynamic_cast для преобразования в производный тип. [119 ]

if(auto d_ptr = dynamic_cast<DerivedAlpha*>(a_ptr)) {
    // do stuff with DerivedAlpha

Если динамический тип не равен DerivedAlpha, динамическое приведение будет безопасно возвращать ноль. Вы не можете динамически отбрасывать от иерархии типов. Поскольку Alpha и Beta не связаны какой-либо структурой наследования, они не могут быть динамически преобразованы взаимно.

0
ответ дан eerorika 5 March 2019 в 15:40
поделиться

Выражение Alpha*a = dynamic_cast<Alpha*>((Alpha*)p); сначала преобразует p в Alpha* с явным приведением стиля c . Затем полученный результат Alpha* пропускается через dynamic_cast<Alpha*>. Использование dynamic_cast<T*> для указателя T* (указатель того же типа, к которому вы пытаетесь привести) всегда будет обеспечивать входной указатель. Его нельзя использовать для подтверждения правильности указателя. Из cppreference для dynamic_cast<new_type>(expression):

Если тип expression точно new_type или менее квалифицированная по cv версия new_type, результатом является значение expression, с типом new_type.

В результате код всегда будет компилироваться и выполняться, а система типов не будет вас защищать. Но итоговое поведение не определено. В случае Beta*b = dynamic_cast<Beta*>((Beta*)p); вы говорите компилятору доверять, что p является Beta*, но это не так. Разыменование результирующего указателя является неопределенным поведением, и dynamic_cast не может защитить вас от этой ошибки.

Если вы попытаетесь удалить явное преобразование типов, вы получите ошибку компилятора. dynamic_cast требует указателя или ссылки на полный тип, а void не является полным типом. Вам нужно будет найти способ отследить фактический тип, указанный вам, и явно преобразовать p в этот тип указателя перед использованием dynamic_cast. Хотя в этот момент, если вы уже знаете тип, к которому нужно применить приведение, это может больше не понадобиться.

Попробуйте использовать общий базовый тип вместо этого или, возможно, используйте std::variant или std::any , если это необходимо.

0
ответ дан François Andrieux 5 March 2019 в 15:40
поделиться

Единственное , что вы можете сделать с помощью указателя void*, это привести его обратно к точно того же типа, что и указатель, приведенный к void* в первом место. Поведение при выполнении чего-либо еще не определено.

Что вы могли бы сделать в вашем случае, так это определить

class Base
{
    public:
    virtual ~Base() = default; // make me a polymorphic type and make 
                               // polymorphic delete safe at the same time.
};

и сделать его базовым классом для Alpha и Beta. Затем обведите указатель Base*, а не void*, и поместите ваши dynamic_cast прямо на p.

Также отметим, что если вы объявите virtual void Speak() = 0; в Base, то ваш код в main станет просто

int main(){ 
    Base* p = new Alpha;
    p->Speak();
    delete p; // ToDo - have a look at std::unique_ptr
}

Как правило, любые типы нежелательны. [ 1119]

0
ответ дан Bathsheba 5 March 2019 в 15:40
поделиться
Другие вопросы по тегам:

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