fat-lobyte hat geschrieben:Zum Thema Casten:
Manchmal geht es einfach nicht ohne. Beispiel Nr. 1:
Code: Alles auswählen
#include <stdlib.h>
...
int* integer_array = (int*) malloc(ARRAYSIZE*sizeof(int));
Wozu gibt es in C++ new?
Ansonsten:
Code: Alles auswählen
union IntegerPointer
{
void * MemoryHandling;
int * IntegerArray;
};
union IntegerPointer intP;
intP.MemoryHandling = malloc( ARRAYSIZE * sizeof( int ) );
intP.IntegerArray[0] = 1;
Mit dem Cast darf man integer_array auch mal nach (char *) konvertieren und auf einen String zeigen lassen. union IntegerPointer lässt das nicht zu.
fat-lobyte hat geschrieben:Beispiel Nr. 2:
Code: Alles auswählen
/* Ich will einfach nur einen Puffer von bytes haben,
* zum beispiel um Netzwerkpakete zusammenzubauen
*/
unsigned char buffer[BUFSIZE];
*(unsigned int*) buffer = packet_length;
*((unsigned short) (buffer+sizeof(unsigned int)) = header_length;
...
C++ Lösung: Klasse erstellen, bestehend aus eigenen Longs, die sich als char-Array zurückgeben lassen.
C Lösung: Funktionen verwenden, die klare Aussagen treffen, was sie tun. Hier könnte man sich wieder mit Unions behelfen, aber hier würde ich Casting akzeptieren, wenn es nur in den passenden Funktionen stattfinden würde.
Code: Alles auswählen
WriteUnsignedint( char ** buffer, unsigned int l )
{
*((unsigned int *) *buffer) = l;
*buffer += sizeof( long );
}
WriteUnsignedShort( char ** buffer, unsigned short s )
{
*((unsigned int *) *buffer) = s;
*buffer += sizeof( short );
}
...
unsigned char buffer[BUFSIZE];
unsigned char ** bufferPos = &buffer;
WriteUnsignedLong( bufferPos, packed_length );
WriteUnsignedShort( bufferPos, header_length );
fat-lobyte hat geschrieben:
Beispiel Nr 3, jetzt aus C++:
Code: Alles auswählen
struct Base
{
bool is_A;
virtual void boringFunction() = 0;
Base(bool _is_A)
: is_A(_is_A)
{}
};
struct DerivedA
{
DerivedA()
: Base(true)
{}
virtual void boringFunction()
{}
void wickedFunction()
{}
}
struct DerivedB
{
DerivedB()
: Base(false)
{}
virtual void boringFunction()
{}
void coolFunction()
{}
}
void handler(Base* base)
{
if (base->is_A)
{
dynamic_cast<DerivedA>(base)->wickedFunction();
}
else
{
dynamic_cast<DerivedA>(base)->coolFunction();
}
}
Grober Designfehler...
Code: Alles auswählen
struct Base
{
bool is_A;
virtual void boringFunction() = 0;
Base(bool _is_A)
: is_A(_is_A)
{}
virtual void handler() = 0;
};
struct DerivedA : public Base // <- gehe ich mal von aus...
{
DerivedA()
: Base(true)
{}
virtual void boringFunction()
{}
void wickedFunction()
{}
void handler()
{
wickedFunction();
}
}
struct DerivedB : public Base
{
DerivedB()
: Base(false)
{}
virtual void boringFunction()
{}
void coolFunction()
{}
void handler()
{
coolFunction();
}
}
Casten ist immer nur ein Armutszeugnis für einen Entwickler. In Beispiel 2 ist casten eine Vereinfachung, Lösung 1 würde hier auch greifen. Lösung 1 ist im letztendlich das gleiche wie Casten, aber es ist vorher klar, dass man nicht überall hinkonvertieren kann, sondern nur zu festgelegte Typen.
Casten in C++ ist ein Zeichen ist so gut wie überhaupt nicht mehr notwendig. Es gibt Fälle mit Templates, da komme ich nicht um Casten rum, um Redundanz zu vermeiden. Bevor ein Cast verwendet wird, sollte man lieber mal ein paar Tage in sich gehen und überlegen, was es für Alternativen gibt.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.