Указание указателя на объект 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();