Tworzę kilka klas Vector2
(X i Y) i Vector3
(X, Y i Z), ale nie wiem, czy Vector3
odziedziczyć Vector2
, czy ponownie zaimplementować zmienne składowe m_x
i m_y
ponownie? Jakie są zalety i wady każdej ze stron (dziedziczenie vs redefinicja).
Edycja: Używam C ++ (VS2010).
c++
architecture
Mark Ingram
źródło
źródło
Vector3
powinno być tylko 3,floats
jeśli chodzi o pamięć. Nie mówię, że to niemożliwe, tylko że nigdy nie widziałem tego w silniku produkcyjnym.floats
. Wiesz, YAGNI, KISS, wszystkie te rzeczy.Vector2
,Vector3
IVector4
bez dziedziczenia ifloats
tylko to naprawdę się de facto standardem w silnikach gier.typedef float real;
;).Odpowiedzi:
Nie, nie powinno. Jedyną rzeczą, której będziesz używać po spadku, jest
x
y
elementy i . Metody stosowane wVector2
klasie nie byłyby przydatne wVector3
klasie, prawdopodobnie przyjmowałyby różne argumenty i wykonywały operacje na innej liczbie zmiennych składowych.źródło
Vector3
IS-NOT-AVector2
(tak powinno nie dziedziczą), aleApple
IS-AFruit
(więc może dziedziczyć). Jeśli wystarczająco przekręcisz swój umysł, pojawi się w nimVector3
HAS-AVector2
, ale utrata wydajności i trudności w kodowaniu oznaczają, że napiszesz całkowicie oddzielne klasy dlaVector3
iVector2
.Jest ciekawa rzecz, którą możesz zrobić w C ++ (nie określiłeś języka, a ta odpowiedź jest głównie dlatego, że myślę, że fajnie jest widzieć alternatywy, chociaż tak naprawdę nie sądzę, aby było to przydatne w większości przypadków).
Za pomocą szablonów możesz zrobić coś takiego:
i można tego użyć w następujący sposób:
Jak powiedziałem, nie sądzę, aby było to przydatne i prawdopodobnie skomplikuje twoje życie, gdy spróbujesz wdrożyć kropkę / normalizację / inne rzeczy i spróbujesz być ogólny z dowolną liczbą wektorów.
źródło
Vector3f v
bardziej nadętyVector3<float> v
typedef
.Niezależnie od prędkości, na pierwsze pytanie należy zadać sobie pytanie, kiedy robi każdy dziedziczenie jest jeśli masz zamiar używać ich polimorficznie. Mówiąc dokładniej, czy jest jakakolwiek sytuacja, w której możesz zobaczyć, jak używasz
Vector3
tak jakby to byłVector2
(który, dziedzicząc po nim, wyraźnie mówisz, że Vector3 „jest-Vector2”).Jeśli nie, to nie powinieneś używać dziedziczenia. Nie należy używać dziedziczenia do udostępniania kodu. Do tego służą komponenty i funkcje zewnętrzne, a nie to, że i tak dzielisz między nimi dowolny kod.
To powiedziawszy, możesz chcieć łatwych sposobów konwersji
Vector3
s naVector2
s, w takim przypadku możesz napisać przeciążenie operatora, które domyślnie skróci jeVector3
do aVector2
. Ale nie powinieneś dziedziczyć.źródło
Vector2
odziedziczeniu z bazyVector<N>
? To ma sens. Ponadto, dlaczego dziedziczenie automatycznie oznacza zachowanie polimorficzne? Jedną z najlepszych rzeczy w C ++ jest to, że możesz mieć dziedzictwo zerowe koszty. Nie trzeba dodawać żadnych wirtualnych metod (w tym wirtualnych destruktorów) doVector<N>
klasy podstawowej .Nie, ponieważ każda metoda również będzie musiała zostać przesłonięta, więc nie będziesz miał pożytku z dziedziczenia po niej.
Jeśli coś, oboje mogliby wdrożyć interfejs Vector. Ponieważ jednak prawdopodobnie nie chcesz dodawać / sub / dot / dst między Vector2 i Vector3, będzie to miało niepożądane skutki uboczne. A posiadanie różnych parametrów itp. Byłoby kłopotliwe.
Więc naprawdę nie widzę żadnych zalet dziedziczenia / interfejsu w tym przypadku.
Przykładem jest framework Libgdx, w którym Vector2 i Vector3 nie mają ze sobą nic wspólnego, oprócz tego samego typu metod.
źródło
Jeśli planujesz użyć karty SIMD tablic prawdopodobnie najlepiej. Jeśli nadal chcesz używać przeciążania operatora, możesz rozważyć użycie interfejsu / mixinu w celu uzyskania dostępu do podstawowej tablicy - na przykład tutaj jest punkt początkowy, który ma tylko (niesprawdzone)
Add
.Zauważ, że nie podałem
X
/Y
/Z
, każdaVectorX
klasa dziedziczy bezpośrednio po tej - z tych samych powodów, które określiły inne osoby. Mimo to wiele razy widziałem tablice używane jako wektory na wolności.Oświadczenie: Mój C ++ może być do kitu, minęło trochę czasu, odkąd go użyłem.
źródło
_aligned_malloc
oznacza, że błąd, który otworzyłem, nie jest tak naprawdę błędem?__m128
rejestru, powinieneś użyć_mm_loadu_ps
zamiast tego. Dobra klasa próbek znajduje się tutaj pod „vectorclass.zip”_mm_loadu_ps
powinien wypracować dla ciebie tę strukturę (gdzie_mm_load_ps
nie będzie). Dodałem również twoją sugestię - możesz edytować pytanie, jeśli uważasz, że szczekam niewłaściwe drzewo (minęło trochę czasu, odkąd użyłem C [++]).Kolejna poważna wada związana z dziedziczeniem Vec3 po Vec2 lub, być może, obojem dziedziczeniem z jednej klasy Vector: kod będzie dużo działałoperacji na wektorach, często w sytuacjach krytycznych czasowo, i w twoim najlepszym interesie leży upewnienie się, że wszystkie te operacje są tak szybkie, jak mogą być - o wiele bardziej niż w przypadku wielu innych obiektów, które nie są dość uniwersalny lub niski poziom. Podczas gdy dobry kompilator dołoży wszelkich starań, aby spłaszczyć wszelkie koszty związane z dziedziczeniem, nadal w większym stopniu polegasz na kompilatorze niż chciałbyś; zamiast tego zbudowałbym je jako struktury z możliwie najmniejszym narzutem, a być może nawet spróbuję uczynić większość funkcji, które ich używają (z wyjątkiem rzeczy takich jak operator +, na które tak naprawdę nie można pomóc), są raczej globalne niż metody na struct. Wczesna optymalizacja jest na ogół zalecana przeciwko, iz nie bez przyczyny,
źródło