(Fortsetzung)
Die C++-Template-Variante gegen die Kot-Explosion sähe so aus:
template <typename T>
int diff(T * arr, size_t n)
{
int result = 0;
for(size_t i = 0; i < n - 1; i++)
result += arr[i+1].member1 - arr[i].member1;
return result;
}
Probleme beim C++-Template-Gedönse gibts natürlich, wenn z.B.
Derived1
und
Derived2
jeweils einen Member
member4
hätten, mit jeweils unterschiedlichem Typ. Dann kann man mit dem
union
das auseinanderhalten, muss aber einen auf die Klasse getemplateten Getter für
member4
schreiben.
Das sind, wie gesagt, Varianten gegen die _Kot-Explosion_. Die zugrundliegende Datenstruktur sieht bei allen gleich aus.
Nun zu den drei Code-Beispielen.
>[1. Code-Beispiel]
>
Dazu die C-Anmerkung: Ohne
union
darf man das nicht, denn die "common initial sequence" für Zeiger auf Objekte, die nicht mit den zugrundeliegenden Objekt übereinstimmen, gilt nur für
union
s. Darüber hinaus verstößt es gegen die strict-aliasing-Rule, da man nun für
arr[i]
zwei Objekte (eines nur temporär) unterschiedlichen Typs hat, womit man nicht mehr mittels
*
oder
->
dereferenzieren darf, wie im Kot gemacht. Du hast aber gesagt, dass das nur Beispielcode für eine mögliche Umsetzung sein soll, deshalb hackt Felix darauf nicht weiter rum.
>Also in deinem Fall wäre die naheliegenste Lösung folgende gewesen:
Das klappt in dem einfachen Beispiel gut. Aber: Sobald die
for
-Schleife nicht mehr in der gleichen Funktion wie die Array-Definition liegt, läuft man wieder in den Fall wie oben rein. Damit wurde das Problem nur verschoben.
Und in einen solchen Fall kann man schnell kommen. Kaum macht man um die Schleife drumrum etwas Komplexeres, oder man will an einer anderen Stelle die gleiche Berechnung durchführen, refaktorisiert man die Schleife raus in eine Funktion. Dann muss man sich bereits fragen, welchen Parameter diese Funktion kriegen soll.
Base *
? Dann kann der Benutzer kein
Derived1
-Array übergeben.
Derived1 *
? Was ist, wenn der Benutzer aber ein
Derived2
-Array hat? Man ist wieder an der gleichen Stelle wie zuvor.
Der Aufrufer, der auch schon mal viele Ebenen drüber im Callstack stehen kann, muss dann wissen und mitteilen, welcher Typ ganz unten im Callstack, in der innersten Berechnungsschleife, zu verwenden sein soll. Das wurde in deinem zweiten Kot-Beispiel auch erkannt: Die Information, die man mein Array-Iterieren über den Typ braucht, nämlich die Größe, wird mit
member_size
runtergereicht.
Das Problem, nämlich das Runterreichen der Information, ist leider auch genau das, was je nach Lösung zur Kot-Explosion führt.