Twórz wymienne typy klas tylko poprzez rzutowanie wskaźnikami, bez konieczności przydzielania żadnych nowych obiektów?

AKTUALIZACJA: Doceniam sugestie „nie chcę tego, chcę tego”. Są przydatne, zwłaszcza gdy są dostarczane w kontekściescenariusz motywujący. Mimo to ... niezależnie od dobroci / zła, zaciekawiło mnie znalezienie trudnego i szybkiego„tak, można to zrobić legalnie w C ++ 11” vs„Nie, nie można zrobić czegoś takiego”.

Chcę „aliasować” wskaźnik obiektu jako inny typ dlajedynym celem dodawania niektórych metod pomocniczych. Alias ​​nie może dodawać członków danych do podstawowej klasy (w rzeczywistości im więcej mogę zapobiec temu, tym lepiej!) Wszystkie aliasy mają jednakowe zastosowanie do każdego obiektu tego typu ... jest to przydatne, jeśli system typów może wskazywać, które alias jest najbardziej odpowiedni.

Nie powinno być żadnych informacji o żadnym konkretnym aliasie, który jest kiedykolwiek zakodowany w obiekcie bazowym. Dlatego czuję, że powinieneś być w stanie „oszukiwać” system typów i po prostu pozwolić, by był to adnotacja ... sprawdzana w czasie kompilacji, ale ostatecznie nieistotna dla castingu wykonawczego. Coś w tym stylu:

Node<AccessorFoo>* fooPtr = Node<AccessorFoo>::createViaFactory();
Node<AccessorBar>* barPtr = reinterpret_cast< Node<AccessorBar>* >(fooPtr);

Pod maską, metoda fabryczna faktycznie tworzyNodeBase klasa, a następnie za pomocą podobnegoreinterpret_cast zwrócić go jakoNode<AccessorFoo>*.

Łatwym sposobem uniknięcia tego jest uczynienie tych lekkich klas, które zawijają węzły i są przekazywane przez wartość. W związku z tym nie potrzebujesz castingu, a jedynie klasy Accessora, które przejmują uchwyt węzła, aby zawinąć ich konstruktor:

AccessorFoo foo (NodeBase::createViaFactory());
AccessorBar bar (foo.getNode());

Ale jeśli nie muszę za to płacić, nie chcę. Wiązałoby się to - na przykład - ze stworzeniem specjalnego typu akcesorium dla każdego rodzaju opakowanego wskaźnika (AccessorFooShared, AccessorFooUnique, AccessorFooWeak itp.). Preferowane jest posiadanie tych typowanych wskaźników dla jednej tożsamości obiektu opartego na wskaźniku i zapewnia ładna ortogonalność.

Wracając do pierwotnego pytania:

Node<AccessorFoo>* fooPtr = Node<AccessorFoo>::createViaFactory();
Node<AccessorBar>* barPtr = reinterpret_cast< Node<AccessorBar>* >(fooPtr);

Wygląda na to, że będzie jakiś sposób na zrobienie tego, co może być brzydkie, ale nie „złamanie zasad”. WedługISO14882: 2011 (e) 5.2.10-7:

Wskaźnik obiektu może być jawnie przekonwertowany na wskaźnik obiektu innego typu.70 Gdy wartość v typu „wskaźnik na T1” jest konwertowana na typ „wskaźnik na cv T2”, wynikiem jest static_cast (static_cast (v)) jeśli zarówno T1, jak i T2 są typowymi układami (3.9), a wymagania wyrównania T2 nie są bardziej rygorystyczne niż wymagania T1, lub jeśli którykolwiek z tych typów jest nieważny. Przekształcenie wartości typu „pointer to T1” na typ „pointer to T2” (gdzie T1 i T2 są typami obiektów i gdzie wymagania wyrównania T2 nie są bardziej rygorystyczne niż te T1) iz powrotem do oryginalnego typu daje oryginał wartość wskaźnika. Wynik innej takiej konwersji wskaźnika jest nieokreślony.

Wiercenie w definicji a„klasa standardowego układu”, znaleźliśmy:

nie ma niestatycznych elementów danych typu non-standard-layout-class (lub tablica takich typów) lub odniesienia, oraznie ma funkcji wirtualnych (10.3) i żadnych wirtualnych klas bazowych (10.1) ima taką samą kontrolę dostępu (klauzula 11) dla wszystkich niestatycznych członków danych, oraznie ma klas bazowych o niestandardowym układzie ialbo nie ma niestatycznego elementu danych w klasie najbardziej pochodnej i co najwyżej jednej klasy bazowej z niestatycznymi składnikami danych, albo nie ma klas bazowych z niestatycznymi składnikami danych, inie ma klas bazowych tego samego typu co pierwszy nie statyczny element danych.

Brzmi jak praca z czymś takim wiązałoby moje ręce trochę bez metod wirtualnych w akcesoriach lub węźle. Jednak C ++ 11 najwyraźniej mastd::is_standard_layout sprawdzać rzeczy.

Czy można to zrobić bezpiecznie? Wygląda na to, że działa w gcc-4.7, ale chciałbym mieć pewność, że nie wywołam niezdefiniowanego zachowania.

questionAnswers(4)

yourAnswerToTheQuestion