2014-12-10 3 views
2

Я использую следующий код для доступа к защищенному члену объекта.В этом случае небезопасно применять объект базового класса к производному классу EMPTY

class Base { 
protected: 
    void foo(); 
}; 

class PublicBase : public Base { 
public: 
    static void bar(Base *obj) { 
     static_assert(sizeof(PublicBase) == sizeof(Base), "Not today"); 
     static_cast<PublicBase *>(obj)->foo(); 
    } 
}; 

Могу ли я предположить, что предоставленный код безопасен в использовании (теоретически и на практике)?

+8

Зачем вам нужно бросить, чтобы сделать это? –

+0

Значит ли слово «безопасно» что-нибудь? В зависимости от значения аргумента функции ваша программа либо имеет неопределенное поведение, либо нет. Также как 'printf'. –

+2

Это безопасно, когда объект действительно имеет этот тип и ни в какое другое время. Если вы думаете, что вам нужно это сделать, вы уже совершаете какую-то ошибку. – EJP

ответ

5

В теории нет. На практике, может быть, до тех пор, пока не задействованы виртуальные функции. Соответствующее место в стандарте является 5.2.9 (2):

Именующее выражение типа «CV1 B», где В представляет собой тип класса, может быть приведен к типу «ссылка на CV2 D , где D - класс, полученный из B, если существует допустимое стандартное преобразование из «указателя на D» в «указатель на B», cv2 - это та же самая cv-квалификация, что и более высокая cv-квалификация, чем, cv1, а B не является ни виртуальным базовым классом D, ни базовым классом виртуального базового класса D. Результат имеет тип «cv2 D.». (...) Если объект типа «cv1 B» на самом деле является подобъектом объекта типа D, результат относится к охватывающему объекту типа D. В противном случае результат литья не определен.

Emphasis mine.

EDIT: Ну, мой первый подход к грязному, но юридическому хакеру не сработал, что приятно, потому что лазейка, о которой я думал, была такой, какой не следует. Там нет никакого способа легально назвать foo на *obj, что я могу найти - так не должно быть, если protected должен иметь какой-либо смысл - так что лучшее, что я могу предложить две идеи для обходных:

Во-первых, если копирование (или перемещения) туда и обратно в порядке

class PublicBase : public Base { 
public: 
    void bar(Base *obj) { 
    // upcast, perfectly legal. make a working copy into self 
    *static_cast<Base*>(this) = *obj; 
    // work 
    foo(); 
    // copy back 
    *obj = *this; 
    } 
}; 

Во-вторых, если вы можете получить от Base и использовать новый класс везде, где бы вы использовали Base раньше:

// use this instead of Base everywhere. 
class BaseWithAccess { 
public: 
    void publicfoo() { foo(); } 
}; 

Кроме этого, у меня ничего нет. Если вы не можете изменить Base, в этом случае вы можете просто сделать foo общественностью.

+0

Спасибо за ответ! Но этот код не будет компилироваться. http://ideone.com/UvJbpm – newbie

+0

Ох. Хм, я подумал, что нужно. Дай мне минуту. – Wintermute

+0

Да, с другой стороны, имеет смысл, что это не так. Боюсь, тогда я могу предложить только незначительные обходные пути с ограничениями. То, что вы пытаетесь сделать, - это именно то, что должны препятствовать спецификаторам доступа к данным. – Wintermute

Смежные вопросы