2013-08-24 17 views
8

Piszę prosty obiekt wektorowy 2D. Będzie zawierał komponenty X i Y oraz długość, krzyżowanie produktów itp. Chodzi o to, chcę mieć strukturę, aby mieć wiele możliwych typów (char, int, float, double, itp.). Zastanawiałem się, jaki byłby najlepszy wybór, by przemyślany projekt mógł wchodzić w interakcje z obiektem? Oto co mam obecnie rozważa:Najlepsze podejście do polimorfizmu struktury w C

1. Czy użytkownik przekazać obiekt wektorowy do wyspecjalizowanych funkcji, takich jak:

Vector2Dt_Dot(Vec2Dt* vector1, Vec2Dt* vector2); 

gdzie „t” jest typem wektora. Jednak problem z tym podejściem polega na tym, że uniemożliwia on różne typy interakcji ze sobą, więc nie mogłem powiedzieć, obliczyć iloczynu punktowego wektora float2d i podwójnego wektora2d. Drugie podejście, a co ja pochylony w kierunku:

2. Czy użytkownik przekazać obiekt wektorowy (y) za nieważne wskaźniki, wraz z ich rodzajów, jak:

Vector2D_Dot(void* vector1, unsigned vector1_type, void* vector2, unsigned vector2_type); 

Oczywiście podejście jest bardziej kompaktowe pod względem API i rozwiązuje powyższy problem, ale kosztem kilku dodatkowych parametrów i bezpieczeństwa typu.

Mogą istnieć inne rozwiązania, o których nie wiem, ale to są te, które obecnie rozważam. Jakie jest według ciebie najlepsze podejście?

+0

@WhozCraig pytanie jest oznaczone 'C', nie' 'C++ –

+0

Nie używaj' * 'void alternatywa; istnieje zbyt wiele sposobów popełniania błędów, których kompilator nie będzie przechwytywał (ponieważ dowolny typ wskaźnika może zostać przekonwertowany na 'void *', w C lub C++). W pewnym momencie to pytanie (w skrócie) miało znacznik C++ i przez dłuższy czas używało notacji typu referencyjnego C++. Jeśli C++ jest istotne, rozważ "wektor wektorowy" >. –

+0

@johnathan leffler: Tak, to był mój błąd. Często przełączam się pomiędzy C i C++. Zdecydowanie użyłbym interfejsu wektoropodobnego, gdyby była opcja w C. – Shokwav

Odpowiedz

11

Co można zrobić, to użyć obiektów polimorficznych. Definiowanie struktury tak:

#define INT_TYPE 0 
#define DOUBLE_TYPE 1 
//more type constants 

typedef struct Vector2D { 
    int type; 
} Vector2D; 

typedef struct Vector2D_int { 
    Vector2D super; 
    int x, y; 
} Vector2D_int; 

typedef struct Vector2D_double { 
    Vector2D super; 
    double x, y; 
} Vector2D_double; 

//more typed vector structures 

Następnie można napisać swoje funkcje do zaakceptowania Vector2D wskazówek, sprawdzać swoich dziedzinach typu i oddać je do odpowiedniego wariantu maszynowy, aby uzyskać dostęp do danych użytkowych.

double Vector2D_length(const Vector2D* vector) { 
    if(vector->type == TYPE_INT) { 
     const Vector2D_int* intVector = (Vector2D_int*)vector; 
     return sqrt(intVector->x * intVector->x + intVector->y * intVector->y); 
    } 
    if(vector->type == TYPE_DOUBLE) { 
     const Vector2D_double* doubleVector = (Vector2D_double*)vector; 
     return sqrt(doubleVector->x * doubleVector->x + doubleVector->y * doubleVector->y); 
    } 
    //other cases follow 
} 

To jest polimorfizm kodowany ręcznie. Wszystko, co musisz zapewnić, to, że pole type jest zawsze ustawione na poprawną wartość (ustawioną raz, gdy zostanie utworzony wektor pisany).

Zaletą takiego podejścia do drugiego pomysłu jest to, że nie trzeba przekazywać typu wektorów w innej zmiennej, co powodowałoby, że używanie wektorów było uciążliwe i podatne na błędy.

Jako alternatywę możesz zdefiniować swoje pole type, aby zawierało wskaźnik do struktury wskaźników funkcji.Użytkownik utworzyłby jeden obiekt struktury wskaźnika funkcji na typ zdefiniowany przez użytkownika i użył go do sprawdzenia, która funkcja ma być używana z danym wektorem. Takie podejście byłoby bardzo bliskie temu, co C++ robi pod maską.

+0

Fantastyczna! Dzięki. – Shokwav

3

Można użyć listę zmiennych argumentów, jego prototyp jest kodowana, na przykład, jak:

int xyz(int a, ...); 

Ten styl wymaga zdefiniowany parametr, w tym przykładzie a, a następnie przez dowolną liczbę parametrów, których typy danych można określić w czasie wykonywania.

Zobacz funkcje i obiekty: va_list; va_start; va_args; i va_end, aby uzyskać pełny opis sposobu przetwarzania zmiennych list argumentów.

Mam nadzieję, że to pomoże. Jeśli masz pytania dotyczące va_list itp., Zapytaj.

0

What I rzeczywiście udał się był następujący:

Stworzyłem klasę baza Vector2D, z następującym układzie:

struct Vector2D_Base; 
typedef struct Vector2D_Base{ 
    M_double (*Vector2D_Get_X)(struct Vector2D_Base* vec); 
    M_double (*Vector2D_Get_Y)(struct Vector2D_Base* vec); 
} Vector2D; 

Jak widać, ten pozwala na ogólne funkcje wektorowe nazwać te aby uzyskać klasy pochodne, wartości x i y zostały przekonwertowane na podwójne, co uniemożliwia elementowi ogólnemu niepokój o różnicę między typami takimi jak char i float. Następnie każdy pochodzi klasa:

#define DEFINE_VECTOR2D(type, name)\ 
typedef struct{\ 
Vector2D_Base vec_base;\ 
type x, y;\ 
} Vector2D##name\ 
Powiązane problemy