ОБНОВЛЕНИЕ: я ценю предложения "не хочу этого, вместо этого хочу это". Они полезны, особенно когда предоставляются в контексте format-database-m">мотивирующий сценарий. Тем не менее... независимо от того, хорошо это или плохо, мне стало любопытно найти жесткое и быстрое "да, это можно сделать легально в C++11" против "нет, это невозможно сделать что-то подобное".
Я хочу "псевдоним" указателя объекта как другого типа с единственной целью добавления некоторых вспомогательных методов. Псевдоним не может добавлять элементы данных в базовый класс (на самом деле, чем больше я могу предотвратить это, тем лучше!) Все псевдонимы одинаково применимы к любому объекту этого типа... просто полезно, если система типов может подсказать, какой псевдоним, вероятно, является наиболее подходящим.
Не должно быть никакой информации о каком-либо конкретном псевдониме, который когда-либо закодирован в базовом объекте. Следовательно, я чувствую, что вы должны иметь возможность «обмануть» систему типов и просто позволить ей быть аннотацией ... проверенной во время компиляции, но в конечном итоге не имеющей отношения к приведению во время выполнения. Что-то в этом роде:
Node<AccessorFoo>* fooPtr = Node<AccessorFoo>::createViaFactory();
Node<AccessorBar>* barPtr = reinterpret_cast< Node<AccessorBar>* >(fooPtr);
Под капотом фабричный метод фактически создает класс NodeBase
, а затем использует аналогичный reinterpret_cast
, чтобы вернуть его как Node<AccessorFoo>*
.
Простой способ избежать этого — создать эти легковесные классы, которые оборачивают узлы и передаются по значению. Таким образом, вам не нужно приведение, только классы Accessor, которые берут дескриптор узла для переноса в свой конструктор:
AccessorFoo foo (NodeBase::createViaFactory());
AccessorBar bar (foo.getNode());
Но если мне не нужно платить за все это, я не хочу. Это может включать, например, создание специального типа средства доступа для каждого типа обернутого указателя (AccessorFooShared, AccessorFooUnique, AccessorFooWeak и т. д.). Использование псевдонимов этих типизированных указателей для одного идентификатора объекта на основе указателя является предпочтительным и обеспечивает хорошая ортогональность.
Итак, вернемся к исходному вопросу:
Node<AccessorFoo>* fooPtr = Node<AccessorFoo>::createViaFactory();
Node<AccessorBar>* barPtr = reinterpret_cast< Node<AccessorBar>* >(fooPtr);
Кажется, что есть какой-то способ сделать это, который может быть уродливым, но не «нарушать правила». Согласно ISO14882:2011(e) 5.2.10-7:
Указатель объекта может быть явно преобразован в указатель объекта другого типа.70 Когда prvalue v типа «указатель на T1» преобразуется в тип «указатель на cv T2», результатом является static_cast(static_cast(v)) если и T1, и T2 являются типами стандартной компоновки (3.9) и требования выравнивания T2 не более строгие, чем требования T1, или если любой из типов недействителен. Преобразование значения prvalue типа «указатель на T1» в тип «указатель на T2» (где T1 и T2 — типы объектов и требования выравнивания T2 не более строгие, чем требования T1) и обратно к исходному типу дает исходный значение указателя. Результат любого другого такого преобразования указателя не указан.
Детализация определения "стандартного макета class", находим:
- не имеет нестатических элементов данных типа non-standard-layout-class (или массива таких типов) или ссылки, и
- не имеет виртуальных функций (10.3) и виртуальных базовых классов (10.1), и
- имеет одинаковый контроль доступа (пункт 11) для всех нестатических элементов данных, и
- не имеет базовых классов нестандартной компоновки, и
- либо не имеет нестатических элементов данных в наиболее производном классе и не более одного базового класса с нестатическими элементами данных, либо не имеет базовых классов с нестатическими элементами данных, и
- не имеет базовых классов того же типа, что и первый нестатический член данных.
Похоже, работа с чем-то вроде этого немного свяжет мне руки без виртуальных методов в аксессорах или узле. Тем не менее, C++11, по-видимому, имеет std::is_standard_layout
для проверки.
Можно ли это сделать безопасно? Кажется, работает в gcc-4.7, но я хотел бы быть уверен, что не вызываю неопределенное поведение.
Node<AccessorFoo>& foo = *new Node<AccessorFoo>;
. Я все равно не понимаю вопроса :) - person iammilind   schedule 27.06.2012