Что я делаю не так с этим указателем? - PullRequest
3 голосов
/ 01 декабря 2008

Я создаю класс GUI для C ++ и много работаю с указателями. Пример вызова:

mainGui.activeWindow->activeWidget->init();

Моя проблема в том, что я хочу привести указатель activeWidget к другому типу. activeWidget имеет тип GUI_BASE. Полученный из BASE у меня есть другие классы, такие как GUI_BUTTON и GUI_TEXTBOX. Я хочу привести указатель activeWidget из GUI_BASE в GUI_TEXTBOX. Я предполагаю, что это будет выглядеть примерно так:

(GUI_TEXTBOX*)(mainGui.activeWindow->activeWidget)->function();

Это не работает, потому что компилятор все еще думает, что указатель имеет тип GUI_BASE. Однако следующий фрагмент кода работает:

GUI_TEXTBOX *textbox_pointer;
textbox_pointer = (GUI_TEXTBOX*)mainGui.activeWindow->activeWidget;
textbox_pointer->function();

Я надеюсь, что моя проблема здесь - просто проблема синтаксиса. Спасибо за помощь:)

Ответы [ 9 ]

18 голосов
/ 01 декабря 2008

Проблема в том, что приведение имеет более низкий приоритет, чем. -> () [] операторы. Вам придется использовать приведение в стиле C ++ или добавить дополнительные скобки:

((GUI_TEXTBOX*)mainGui.activeWindow->activeWidget)->function();  // Extra parentheses
dynamic_cast<GUI_TEXTBOX*>(mainGui.activeWindow->activeWidget)->function();  // C++ style cast
9 голосов
/ 01 декабря 2008

Вы не должны использовать приведение в стиле C.

Вам необходимо использовать динамическое приведение C ++. Это позволит вам проверить, что объект на самом деле является GUI_TEXTBOX, прежде чем вызывать метод для него.

GUI_TEXTBOX* textboxPointer  = dynamic_cast<GUI_TEXTBOX*>(mainGui.activeWindow->activeWidget);
if (textboxPointer)
{
     // If activeWidget is not a text box then dynamic_cast
     // will return a NULL.
     textboxPointer->textBoxMethod();
}

// or 

dynamic_cast<GUI_TEXTBOX&>(*mainGui.activeWindow->activeWidget).textBoxMethod();

// This will throw bad_cast if the activeWidget is not a GUI_TEXTBOX

Обратите внимание, что приведение в стиле C и reinterpret_cast <> () не гарантированно сработают в этой ситуации (хотя на большинстве компиляторов они будут работать [но это всего лишь аспект реализации, и вам повезло]). Все ставки отключены, если объект, назначенный activeWidget, на самом деле использует множественное наследование, в этой ситуации вы начнете видеть странные ошибки с большинством компиляторов, если вы не используете dynamic_cast <> ().

4 голосов
/ 01 декабря 2008

Вам просто нужно больше скобок:

((GUI_TEXTBOX*)(mainGui.activeWindow->activeWidget))->function();

На самом деле, это тоже будет работать:

((GUI_TEXTBOX*)mainGui.activeWindow->activeWidget)->function();
3 голосов
/ 01 декабря 2008

Как и другие отмечали:

((GUI_TEXTBOX*)(mainGui.activeWindow->activeWidget))->function();

Причина в том, что оператор -> имеет более высокий приоритет, чем приведение типов.


Я поставлю здесь еще один плагин для правила Стива Уоллина из "Практического С":

В пятнадцати правилах предшествования C (&& предшествует раньше, чем || ? :). Практичный программист уменьшает это к двум:

1) Умножение и деление приходят до сложения и вычитания.

2) Поставьте круглые скобки вокруг всего еще.


И последнее замечание: снижение рейтинга может быть опасным, см. Ответ Мартина Йорка для получения информации об использовании dynamic_cast<> для безопасного выполнения приведения.

1 голос
/ 02 декабря 2008

Есть две стратегии. Один из них - «быстро провалиться»: если вы приведете к неверному типу, вы получите исключение, поэтому вы сразу заметите, что вы применили к неправильному типу. Другой - «быстро бегать»: проверка типа приведения не выполняется. Это приведение следует использовать только в том случае, если вы знаете, что не можете ошибаться, или если у вас нет полиморфного типа с основанием или производным. Я рекомендую следующее в зависимости от ваших потребностей (не забывайте сохранять константу при касте):

dynamic_cast<GUI_TEXTBOX&>(*mainGui.activeWindow->activeWidget).function();

Fail fast : бросает std::bad_cast, если вы используете неверный тип.

static_cast<GUI_TEXTBOX*>(mainGui.activeWindow->activeWidget)->function();

Быстрый запуск : проверка времени выполнения не выполняется. Так что это не подведет быстро. Скорее, это приведет к неопределенному поведению, если вы приведете к неправильному типу. Осторожно!

1 голос
/ 01 декабря 2008

Это вопрос порядка операторов (приоритет оператора). Рассмотрим код, который вы пробовали, который не работал:

(GUI_TEXTBOX *) (mainGui.activeWindow-> activeWidget) -> функция ();

Здесь оператор -> имеет более высокий приоритет, чем ваш актерский состав. Вот почему ваш другой пример кода работает. В другом примере вы сначала явно приводите, а затем вызываете функцию. Чтобы упростить его, попробуйте добавить еще один набор скобок, чтобы код выглядел следующим образом:

((GUI_TEXTBOX *) (mainGui.activeWindow-> activeWidget)) -> функция ();

0 голосов
/ 01 декабря 2008
if( GUI_TEXTBOX* ptr = 
      dynamic_cast<GUI_TEXTBOX *>(mainGui.activeWindow->activeWidget) )
{
   ptr->function();
}

Причина, по которой вы хотите это сделать, заключается в том, что указатель, который вы пытаетесь привести, может на самом деле не указывать на объект GUI_TEXTBOX, и вы хотите убедиться в этом, прежде чем вызывать для него методы текстового поля. Динамическое приведение C ++ - то, что вам нужно для этого.

0 голосов
/ 01 декабря 2008

-> имеет более высокий приоритет, чем (приведение), поэтому доступ к члену выполняется перед приведением. Смотрите здесь для определения приоритета оператора: http://www.cppreference.com/wiki/operator_precedence

Как указано выше, вам нужно больше скобок.

0 голосов
/ 01 декабря 2008
((GUI_TEXTBOX*)(mainGui.activeWindow->activeWidget))->function();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...