PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Konstruktorproblem in einer Union


Neomi
2005-04-29, 13:24:12
Wenn ich eine Struktur in einer Union verwenden will, darf diese Struktur keinen Defaultkonstruktor haben, ich brauche eigentlich auch keinen Defaultkonstruktor. Da ich aber einen parametrisierten Konstruktor haben möchte, muß ich ebenfalls einen Defaultkonstruktor liefern, der zwar nichts tut, aber eben doch vorhanden ist. Ansonsten kann ich keine uninitialisierten Variablen des Typs anlegen.

Hier der konkrete Fall:

struct ColRGB
{
float r;
float g;
float b;

ColRGB () { }

ColRGB (float r, float g, float b)
{
this->r = r;
this->g = g;
this->b = b;
}
};

struct ColRGBA
{
union
{
ColRGB rgb;

struct
{
float r;
float g;
float b;
};
};

float a;

ColRGBA () { }

ColRGBA (float r, float g, float b, float a)
{
this->r = r;
this->g = g;
this->b = b;
this->a = a;
}
};

Leider funktioniert die Union dank des Defaultkonstruktors nicht und ein "const" ist leider bei Konstruktoren nicht erlaubt. Dabei will ich doch nur etwas in der Richtung nutzen können:

ColRGBA Color (0.0f, 0.0f, 0.0f, 1.0f);
Color.rgb = ColRGB (0.5f, 0.5f, 0.5f);

Ich habe es jetzt auf diese Art versucht:

struct ColRGBA
{
ColRGB rgb;

float & r;
float & g;
float & b;
float a;

ColRGBA () : r (rgb.r), g (rgb.g), b (rgb.b) { }

ColRGBA (float r, float g, float b, float a) : r (rgb.r), g (rgb.g), b (rgb.b)
{
this->r = r;
this->g = g;
this->b = b;
this->a = a;
}
};

Das funktioniert zwar, leider benötigt jede Referenz ihren eigenen Speicherplatz und die Struktur erreicht eine Größe von 28 statt 16 Bytes.

Kennt jemand vielleicht eine elegante Lösung, wie ich direkt auf r, g, b und a, aber auch auf rgb als Ganzes zugreifen kann, ohne daß die Struktur größer wird als 16 Bytes?

Coda
2005-04-29, 13:34:17
Öh wie wär's einfach mit

struct ColRGB
{
float r;
float g;
float b;

ColRGB () { }

ColRGB (float r, float g, float b)
{
this->r = r;
this->g = g;
this->b = b;
}
};

struct ColRGBA : public ColRGB
{
float a;

ColRGBA () { }

ColRGBA (float r, float g, float b, float a)
{
this->r = r;
this->g = g;
this->b = b;
this->a = a;
}
};

Neomi
2005-04-29, 14:35:11
Vererbung löst das Problem leider nicht.

inline ColRGB operator * (ColRGB & Col1, ColRGB & Col2)
{
return (ColRGB (Col1.r * Col2.r, Col1.g * Col2.g, Col1.b * Col2.b));
}

inline ColRGBA operator * (ColRGBA & Col1, ColRGBA & Col2)
{
return (ColRGBA (Col1.r * Col2.r, Col1.g * Col2.g, Col1.b * Col2.b, Col1.a * Col2.a));
}

Von solchen habe ich natürlich einige, mit der normalen Vererbung kann ich die nur per ständigem Casting nutzen. Und wenn ich das Ergebnis einer RGB-Operation dem RGB-Teil einer RGBA-Farbe zuweisen will, ohne Alpha anzutasten, dann geht das einfach nicht. Ein Casting von ColRGB auf ColRGBA soll nämlich Alpha auf 1.0f setzen.


ColRGB Col1 (0.5f, 0.5f, 0.5f);
ColRGBA Col2 (0.0f, 0.0f, 0.0f, 1.0f);

Col2 = Col1; // geht nicht, braucht einen extra Assignment-Operator

((ColRGB) Col2) = Col1; // r, g und b bleiben bei 0.0f

Es gibt natürlich ein paar leichte "Lösungen", die aber keinesfalls elegant sind und dadurch eher Nachteile haben.

1. Einmal "ColRGB rgb" als Member. Dann gibt es aber kein "Col2.r" mehr, sondern ein "Col2.rgb.r", was doof aussieht.

2. Extramethoden "ColRGB ColRGBA::GetRGB ()" und "void ColRGBA::SetRGB (ColRGB rgb)", auch doof.

Coda
2005-04-29, 14:45:24
Und wieso machst du bei dem ColRGBA nicht einfach nen "operator ColRGB()" und "ColRGBA(ColRGB)" dazu?

Neomi
2005-04-29, 14:58:34
Und wieso machst du bei dem ColRGBA nicht einfach nen "operator ColRGB()" und "ColRGBA(ColRGB)" dazu?

Einen "operator ColRGB()" deshalb nicht:

ColRGBA Col2 (0.0f, 0.0f, 0.0f, 1.0f);
((ColRGB) Col2) += ColRGB (0.2f, 0.2f, 0.2f);

Das funktioniert nicht, da die Operation auf eine temporär erstellte Version angewendet wird. Col2 selbst bleibt unverändert.

Einen ColRGBA-Konstruktor mit ColRGB-Argument und einen Assignment-Operator sowie ein Casting von ColRGB nach ColRGBA habe ich, aber die machen was anderes. Alpha wird in all den Fällen auf 1.0f gesetzt.

Coda
2005-04-29, 15:16:54
Noch was: Wieso speicherst du nicht beides einfach in nem ColRGBA und lässt RGB ganz weg? Das wird aus Alignmentgründen eh gleich groß sein...

Neomi
2005-04-29, 15:53:46
Auf ColRGB als einzelnen Typ könnte ich wirklich verzichten. Dann bleibt leider weiterhin das Problem, daß jede Standardoperation, die man theoretisch sowohl auf RGB als auch auf RGBA anwenden könnte, nur für RGBA verfügbar wäre.

Ich habe jetzt jedenfalls eine Lösung genommen, die zwar nicht ganz perfekt ist, aber doch recht gut funktioniert:

struct ColRGB
{
float r;
float g;
float b;
};

struct ColRGBA
{
union
{
ColRGB rgb;

struct
{
float r;
float g;
float b;
};
};

float a;
};

inline ColRGB Color (float r, float g, float b)
{
ColRGB Color = { r, g, b };

return (Color);
}

inline ColRGBA Color (float r, float g, float b, float a)
{
ColRGBA Color = { r, g, b, a };

return (Color);
}

Die Nachteile dabei sind, daß einmal Definitionen wie "ColRGB Col (0.0f, 0.0f, 0.0f)" nicht mehr funktionieren und dann noch der Name der Funktion, die eine Struktur zusammenbastelt, anders sein muß als der Name des Typs selbst. Ein "inline ColHSV Color (float h, float s, float v)" werde ich also aufgrund der Signatur der Funktion leider nicht mehr hinzufügen können. Deshalb habe ich diese "Lösung" schonmal verworfen, aber es ist wohl noch die beste Alternative.

micki
2005-04-29, 17:14:39
Leider funktioniert die Union dank des Defaultkonstruktors nicht und ein "const" ist leider bei Konstruktoren nicht erlaubt. Dabei will ich doch nur etwas in der Richtung nutzen können:

ColRGBA Color (0.0f, 0.0f, 0.0f, 1.0f);
Color.rgb = ColRGB (0.5f, 0.5f, 0.5f);


das geht so

ColRGBA c = {0.f,3.f,2.f,0.5f};
ColRGB b={0.5f,0.5f,0.5f};
c.rgb = b;


MfG
micki

sehe gerade du hast selbst diese lösung... ja ich bin doof und out mich hier ;)