2011-10-14 25 views
9

Powiedzmy mam dwie różne klasy, zarówno reprezentacji danych współrzędnych 2D w taki sam sposób wewnętrznego tak:Bezpieczeństwo odlewania między wskazówkami dwóch identycznych klas?

class LibA_Vertex{ 
    public: 
    // ... constructors and various methods, operator overloads 
    float x, y 
}; 

class LibB_Vertex{ 
    public: 
    // ... same usage and internal data as LibA, but with different methods 
    float x, y 
}; 


void foobar(){ 
    LibA_Vertex * verticesA = new LibA_Vertex[1000]; 
    verticesA[50].y = 9; 
    LibB_Vertex * verticesB = reinterpret_cast<LibB_Vertex*>(vertexA); 
    print(verticesB[50].y); // should output a "9" 
}; 

Biorąc pod uwagę dwie klasy są identyczne, a funkcja powyżej, mogę niezawodnie liczyć na tej konwersji wskaźnika działa w sposób oczekiwany w każdym przypadku?

(W tle potrzebuję prostego sposobu na handel tablicami wierzchołków między dwiema oddzielnymi bibliotekami, które mają identyczne klasy Vertex i chcę uniknąć niepotrzebnego kopiowania tablic).

Odpowiedz

13

C++ 11 dodał pojęcie o nazwie zgodne z układem, które mają zastosowanie tutaj.

Dwa standardowym układ struct (punkt 9) typy układ zgodny jeśli mają taką samą liczbę non-statycznych danych i odpowiadających non-statycznymi członkami danych (w kolejności zgłoszenia) mają Zgodne z układem typy: (3.9).

gdzie

Klasa standardowego układu jest klasa:

  • ma nie-statycznych pól grupy typu nie-standardowych układów (lub szeregu takich typów) lub odniesienie,
  • nie ma funkcji wirtualnych (10.3) i nie ma wirtualnych klas bazowych (10.1),
  • ma tę samą kontrolę dostępu (Rozdział 11) dla wszystkich niestatycznych danych m embers,
  • nie ma niestandardowych klas podstawowych,
  • nie ma żadnych niestatycznych elementów danych w najbardziej pochodnej klasie i najwyżej jednej klasie bazowej z niestatycznymi elementami danych lub nie ma klas podstawowych z niestatyczne elementy danych i
  • nie ma klas podstawowych tego samego typu, co pierwszy niestatyczny element danych.

standardowym układ struct jest klasą standardowym układ zdefiniowana z klasa kluczstruct lub klasa kluczclass.

unia standardowym układ jest klasą standardowym układ zdefiniowana z klasa kluczunion.

Wreszcie

wskaźniki do cv wykwalifikowanych i niewykwalifikowanych wersje CV (3.9.3) o układ zgodny rodzaje mają te same wymagania reprezentacji wartość i wyrównania (3.11).

Który gwarantuje, że reinterpret_cast może zmienić wskaźnik na jeden typ w wskaźnik na dowolny typ zgodny z układem.

+3

Innym dobrze zdefiniowanym sposobem wykonywania tych konwersji jest użycie unii z typową początkową sekwencją (jak zezwala na to "§9.2/19"). – Mankarse

+0

Oh! Cóż, C++ 11 na ratunek. Mam tylko nadzieję, że była to jedna z rzeczy, które VS2010 zdecydowało się dodać, kiedy poszła na wiśnie wybierając standard. –

+1

@ Clairevoire: Jest to jedna z rzeczy, która zawsze działała w praktyce, nawet jeśli formalnie jest zabroniona. Nie oczekuję, że każdy twórca kompilatora musiałby "dodać" wsparcie. –

1

Chciałbym zawrzeć tę konwersję w klasie (tak, że jeśli chcesz zmienić platformę lub coś takiego, to przynajmniej zlokalizowane w jednym miejscu), ale tak, powinno być możliwe.

Będziesz także chciał użyć reinterpret_cast, a nie static_cast.

+0

W porządku, mój błąd! Poprawiono pytanie –

1

Teoretycznie jest to niezdefiniowane zachowanie. Może jednak działać w niektórych systemach/platformach.

Sugerowałbym, że należy spróbować połączyć 2 do 1. klasy tj

class Lib_Vertex{ 
// data (which is exactly same for both classes) 
public: 
// methods for LibA_Vertex 
// methods for LibB_Vertex 
}; 

dodawania metod do class nie wpłynie na jego rozmiar. Być może będziesz musiał nieco zmienić swój projekt, ale warto.

+0

Zazwyczaj używałbym też czegoś takiego. Wciąż jednak musiałbym robić kopie tablic. Jedna biblioteka (2d physics lib) zwraca całe tablice wierzchołków za pomocą swojej wewnętrznej klasy Vertex, którą następnie muszę podać do drugiej biblioteki (2d rendering lib), która akceptuje tablice jej wewnętrznej klasy Vertex. –

0

Technicznie jest to niezdefiniowane zachowanie. W rzeczywistości, gdyby ten sam kompilator był używany do kompilowania obu klas, będą one miały ten sam układ w pamięci, jeśli pola są zadeklarowane w tej samej kolejności, mają te same typy i ten sam poziom dostępu.

Powiązane problemy