Указание указателя на объект void * в С++
Я слишком много читал StackOverflow и начал сомневаться во всем коде, который я когда-либо писал, я все время думаю: "Это что-то вроде undefined?" даже в коде, который работал целую вечность.
Итак, мой вопрос: безопасно ли и четко определено поведение, чтобы направить указатель на объект (в данном случае абстрактные классы интерфейса) на void *, а затем позже вернуть их к исходному классу и вызвать метод, используя их?
Я полностью понимаю, что код, который делает это, вероятно, ужасен. Я бы даже не подумал написать это сейчас (это старый код, который я действительно не хочу менять), поэтому я не ищу обсуждения лучших способов сделать это. Я уже знаю, как лучше писать, если я когда-нибудь это повторю. Но если это действительно сломано, чтобы полагаться на это на С++, тогда мне придется посмотреть на изменение кода, если это просто ужасный код, а затем его изменение не будет приоритетом.
У меня не было бы никаких сомнений по поводу чего-то такого простого года или двух назад, но по мере того, как мое понимание С++ возрастает, я нахожу, что все больше беспокоится о безопасности кода под стандартами, даже если он работает отлично. Возможно, чтение слишком большого - это плохо для производительности иногда: P
Ответы
Ответ 1
Вы в безопасности.
Из проекта С++ (0x),
& sect; 5.2.9/13 (для static_cast
):
Значение указателя типа для объекта, преобразованного в "указатель на cv void
" и обратно, возможно с другой cv-квалификацией, должно иметь свое первоначальное значение.
& sect; 5.2.10/7 (для reinterpret_cast
):
Преобразование rvalue типа "указатель на T1
" в тип "указатель на T2
" (где T1
и T2
- это типы объектов, а требования к выравниванию T2
не являются более строгими, чем те из T1
) и обратно к исходному типу дает исходное значение указателя.
(Конечно, приведение к несвязанному классу - это поведение undefined.)
Ответ 2
Итак, мой вопрос: безопасно ли и четко определено поведение, чтобы направить указатель на объект (в данном случае абстрактные классы интерфейса) на void *, а затем позже вернуть их к исходному классу и вызвать метод, используя их?
Да - до тех пор, пока вы вернетесь к тому же типу. В противном случае корректировки указателя базового класса могут уничтожить значение указателя.
На практике это (возможно) применимо только при использовании множественного наследования: указатели на производный класс могут отличаться по своему физическому адресу от указателей на их базовый класс.
Ответ 3
Мы обычно используем эту технику, чтобы избежать использования операторов switch в каждом отдельном классе на основе используемой вами среды (веб-интерфейс, Windows, Linux и т.д.).
Используйте void **
для ссылок.
void ** detailObject;
Создайте функцию для возврата объекта, на который ссылается:
TheObject *TheClass::GetObject(){
TheObject *object = (TheObject*)object;
return object;
}
Просто используйте функцию как объект с этого момента. например GetObject()->Go()
;