Приведение указателя на объект void * в C ++ - PullRequest
13 голосов
/ 10 апреля 2010

Я слишком много читаю StackOverflow и начал сомневаться во всем коде, который когда-либо писал, я продолжаю думать: «Это неопределенное поведение?» даже в коде, который работал целую вечность.

Так что мой вопрос - это безопасное и четко определенное поведение - приводить указатель на объект (в данном случае абстрактные классы интерфейса) к пустоте *, а затем приводить их обратно к исходному классу и вызывать метод, используя их?

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

Я бы не сомневался в чем-то таком простом год или два назад, но по мере того, как мое понимание C ++ возрастает, я на самом деле обнаруживаю, что все больше и больше беспокоюсь о безопасности кода в соответствии со стандартами, даже если он отлично работает. Возможно, чтение слишком большого количества переполнения стека иногда плохо для производительности: P

Ответы [ 3 ]

16 голосов
/ 10 апреля 2010

Вы в безопасности.

Из черновика C ++ (0x),

& 5.25 / 13 (для static_cast):

Значение указателя типа на объект, преобразованное в «указатель на cv void» и обратно, возможно с другой квалификацией cv, должно иметь свое первоначальное значение.

& 5.2.2 / 7 (для reinterpret_cast):

Преобразование значения типа «указатель на T1» в тип «указатель на T2» (где T1 и T2 являются типами объектов и где требования выравнивания T2 не являются более строгими, чем T1) и обратно в исходный тип возвращает исходное значение указателя.

(Конечно, приведение к несвязанному классу - неопределенное поведение.)

8 голосов
/ 10 апреля 2010

Так что мой вопрос - это безопасное и четко определенное поведение - приводить указатель на объект (в данном случае абстрактные классы интерфейса) к пустоте *, а затем приводить их обратно к исходному классу и вызывать метод, используя их?

Да - пока вы возвращаетесь к типу точно такого же . В противном случае настройки указателя базового класса могут уничтожить значение указателя.

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

1 голос
/ 19 сентября 2012

Мы обычно используем эту технику, чтобы избежать использования операторов switch в каждом отдельном классе в зависимости от среды, которую вы используете (в Интернете, Windows, Linux и т. Д.)

Используйте void ** для ссылок.

void ** detailObject;

Создать функцию для возврата ссылочного объекта:

TheObject *TheClass::GetObject(){
    TheObject *object   =   (TheObject*)object;
    return object;
}

Теперь используйте функцию как объект. например GetObject()->Go();

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