Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem C++: Namespace&Klasse&Operator
Einfachkrank
2005-03-29, 20:19:40
Moin,
habe hier folgende Klasse in nem Namespace deklariert:
namespace NVector_std {
class _MDLL CVector2
{
public:
CVector2(void);
CVector2(const float &s);
CVector2(const float &a, const float &b);
CVector2(const CVector2 &vec);
const CVector2 operator+ (const CVector2 &vec);
const CVector2 operator- (const CVector2 &vec);
const CVector2 operator/ (const CVector2 &vec);
const CVector2 operator* (const CVector2 &vec);
// ...
};
}
In der Source Datei habe ich folgendes:
const CVector2 NVector_std::CVector2::operator+(const CVector2 &vec)
{
return CVector2(x + vec.x, y + vec.y);
}
Und der Compiler spuckt folgendes aus:
e:\save\windows\visual development\visual c++\m3d_project\m3d_b\m3d_vector_std.cpp(25) : error C2143: syntax error : missing ';' before 'tag::id'
e:\save\windows\visual development\visual c++\m3d_project\m3d_b\m3d_vector_std.cpp(25) : error C2734: 'CVector2' : const object must be initialized if not extern
e:\save\windows\visual development\visual c++\m3d_project\m3d_b\m3d_vector_std.cpp(25) : fatal error C1004: unexpected end of file found :D
Was muss ich denn machen, damit der die Schnauze hält? :rolleyes:
MFG Einfachkrank
Moin,
habe hier folgende Klasse in nem Namespace deklariert:
const CVector2 operator+ (const CVector2 &vec);
const CVector2 operator- (const CVector2 &vec);
const CVector2 operator/ (const CVector2 &vec);
const CVector2 operator* (const CVector2 &vec);
Was muss ich denn machen, damit der die Schnauze hält? :rolleyes:
ich würde referenzen zurückgeben, denn sonst müsste bei dem return in der implementierung in ein const object geschrieben werden, was ja nicht geht...
Chris Lux
2005-03-29, 21:39:02
sorry keks war weg, das war ich ;)
achja, ich würde den namespace dann auch konsequent in der implementierung einsetzen, dh auch bei dem const CVector2.
Einfachkrank
2005-03-29, 21:46:36
Ahh ... wie mache ich das? Kannst du mir grad mal Code posten?
Chris Lux
2005-03-29, 22:17:04
Ahh ... wie mache ich das? Kannst du mir grad mal Code posten?
hast doch alles schon:
namespace NVector_std {
class _MDLL CVector2
{
public:
CVector2(void);
CVector2(const float &s);
CVector2(const float &a, const float &b);
CVector2(const CVector2 &vec);
const CVector2& operator+ (const CVector2 &vec);
const CVector2& operator- (const CVector2 &vec);
const CVector2& operator/ (const CVector2 &vec);
const CVector2& operator* (const CVector2 &vec);
// ...
};
}
In der Source Datei habe ich folgendes:
const NVector_std::CVector2 NVector_std::CVector2::operator+(const NVector_std::CVector2 &vec)
{
return NVector_std::CVector2(x + vec.x, y + vec.y);
}
Einfachkrank
2005-03-29, 22:30:01
Achsooooo! Jetzt gehen mir Lichter auf! Danke!!!
Einfachkrank
2005-03-29, 22:35:57
Halt! Noch en Problem: Das Übergeben der Referenz funktioniert noch nicht ganz... Aber geht das überhaupt, denn die Variable ist doch temporär...
Ne geht nicht, das mit der Referenz ist Schwachsinn.
Die Namespace Notation in der C++ Datei ist mir auch neu. Aber C++ überrascht einen immer wieder ;)
micki
2005-03-29, 22:58:31
referenzen zurück zu geben wäre falsch, da man dann auf ein objekt zeigt, das schon zerstört wurde, nachdem man aus der funktion ging.
const objekte zurück zu geben ist ok, denn operatoren und copy-constructors sollten auch ein const objekt bzw const reference schlucken.
const objekte muss man nicht zurück geben, man darf auch normale objekte zurückgeben, jedoch schützen const objekte vor sowas wie
if(a+b=c)...
genaueres was für vor und nachteile const objekte haben unter http://www.cuj.com/documents/s=8246/cujcexp2102alexandr/
wobei es dort darum geht elegant das kopieren von temporärdaten zu umgehen.
aber nochmals, niemals referenzes auf objekte zurückgeben die lokale variablen in funktionen waren, sonst passiert bullshit!!!!!!!!!!
MfG
micki
In der Source Datei habe ich folgendes:
const NVector_std::CVector2 NVector_std::CVector2::operator+(const NVector_std::CVector2 &vec)
{
return NVector_std::CVector2(x + vec.x, y + vec.y);
}
Wieso nicht einfach namespace NVector_std {...} auch in der Source-Datei verwenden? ;)
Chris Lux
2005-03-30, 08:59:16
Wieso nicht einfach namespace NVector_std {...} auch in der Source-Datei verwenden? ;)
er hat damit angefangen ;) man kann auch davor einfach using namespace NVector_std; schreiben.
zu den refernenzen, sorry erstmal. ich hab das mit dem += operator verwechselt, für das normale + ist es richtig keine referenz zu nutzen, dann macht aber auch das const keinen sinn (also IMO weg damit).
micki
2005-03-30, 09:33:47
dann macht aber auch das const keinen sinn (also IMO weg damit).
For good reasons, some authors recommend constifying return values as well [7]. Continuing the old rules:
4. When a function returns a user-defined object by value, return a const value. Example:
const String operator+(const String& lhs,
const String& rhs);
The idea underlying rule 4 is to make user-defined operators behave much as built-in operators by forbidding wrong expressions such as if (s1 + s2 = s3), when the intent is to say if (s1 + s2 == s3). If operator+ returns a const value, this particular bug will be detected at compile time.
es macht also sinn, erzwingt es doch bei eigenen objekten das gleiche verhalten wie bei vorhandenen primitiven (wichtig, wenn man einen wrapper schreibt z.b. für float um möglichst einfach zwischen fpu und sse/3dnow zu testen).
ob man es denn nun nutzt oder nicht ist aber in vielen fällen nur philosophie bei der man nicht streiten muss.
ich schreibs hier nur nochmal hin um drauf hinzuweisen, dass es nicht "sinnlos" ist :)
MfG
micki
Einfachkrank
2005-03-30, 10:28:03
Wieso nicht einfach namespace NVector_std {...} auch in der Source-Datei verwenden? ;)
Das sagst du mir jetzt, nachdem ich überall das NVector_std davor geklemmt habe?! :D :D :D Mann, die Welt ist so gemein!
Great Thanks, Einfachkrank :uup:
er hat damit angefangen ;) man kann auch davor einfach using namespace NVector_std; schreiben.
Jein, nur wenn die darin verwendeten Symbole eindeutig sind, so dass es nicht zu Namenskonflikten kommt. Außerdem macht der namespace-Block syntaktisch deutlicher, dass es sich hier um Methodendefinitionen in diesem Namespace dreht, also dass man den Namespace nicht "verwendet", sondern seinen Inhalt definiert.
Chris Lux
2005-03-31, 01:11:49
Jein, nur wenn die darin verwendeten Symbole eindeutig sind, so dass es nicht zu Namenskonflikten kommt. Außerdem macht der namespace-Block syntaktisch deutlicher, dass es sich hier um Methodendefinitionen in diesem Namespace dreht, also dass man den Namespace nicht "verwendet", sondern seinen Inhalt definiert.
;) IMO sollten in einem namespace symbole eindeutig sein, wenn nicht kommt es auch mit deiner notation zu konflikten, welche nur mit der ns:: notation lösbar sind. in einem source file sollten sich jedoch dein weg und meiner IMO nichts nehmen, von daher geschmackssache, und meiner war auch nur ein weiterer hinweis, wie man das problem lösen kann.
mmh, nach dem ersten überfliegen würde ich außer den schon genannten noch 2 sachen ändern:
1. die operatoren aus der klasse rausnehmen, allein schon der symetrie wegen. eröffnet auch mehr möglichkeiten für überladungen von außen, was z.b. bei generischer programmierung wichtig werden kann. wenn die klasse hierfür zuwenig schnittstellen hat, macht man halt ein friend draus.
2. rückgabe eines benannten objektes. warum das gut ist kann man z.b. in "effective c++" von scott meyers nachlesen oder einfach mal googlen. kurz gesagt kann der code vom compiler so einfacher optimiert werden. das rückgegebene objekt kann dann häufig direkt im ziel konstruiert werden ohne den umweg des kopier-ctors.
const CVector2 operator +(const CVector2& lhs, const CVector2& rhs)
{
const CVector2 ret(lhs.x + rhs.x, lhs.y + rhs.y);
return ret;
}
bei 1. kann man sicher vortrefflich streiten, was besser ist. ich denke, man sollte die eigentliche klassenschnittstelle so minimal (aber vollständig) wie möglich halten. alles andere kann dann von außen nachgereicht werden. (namespaces kann man übrigens bieliebig oft schließen und wieder neu öffnen). so kann man als nutzer dieser klasse z.b. auswählen, ob man optimierte versionen der operatoren haben möchte, eine version mit zusätzlichen laufzeitüberprüfungen oder ob man nicht doch lieber eigene angepasste operatoren implementiert. die verschiedenen varianten müssen dann nicht alle in einer klassendefinition oder in einer headerdatei stehen.
bei 2. müsste man mal mit verschiedenen compilern testen, obs wirklich was an performance bringt...
Chris Lux
2005-03-31, 07:46:30
bei 1. kann man sicher vortrefflich streiten, [...]
ach pfuuuu... ähh KiBa, sag sowas doch nicht zu mir ;)
nur spass, ich muss dir da vollkommen recht geben, nur was meinst du mit symetrie?
aber wenn wir schon bei tipps sind, ich find folgendes für vectorklassen noch super praktisch:
struct vec2_t
{
[...]
union
{
struct
{
float x, y;
};
float vec[2];
};
};
so kann man einen solchen vektor mit x o. y indizieren, und intern optimierungsfreundliche schleifen für die operationen basteln (macht sicher erst sinn bei mehr komponenten oder matrizen). find ich ganz praktisch ;)
micki
2005-03-31, 08:46:05
kann man sicher vortrefflich streiten, was besser ist.[/code]
natürlich, deswegen sollte man posts wie deine gleich lassen, provoziert nur ;)
[QUOTE=KiBa]
ich denke, man sollte die eigentliche klassenschnittstelle so minimal (aber vollständig) wie möglich halten.
an diese grundlage hällt sich natürlich jeder ... aber jeder auf seine weise...
alles andere kann dann von außen nachgereicht werden.
wobei man grundsätzlich bei c++ auf c-artigen stil verzichten sollte.
btw. ich glaube du meintest "efficient c++" und nicht "effective c++", denn im ersten steht was über RVO im zweiten weder über RVO noch NRVO.
und mein optimierungstip ist: http://www.tantalon.com/pete/cppopt/final.htm
MfG
micki
@luuux
mit symetrisch meine ich, wenn z.b. der operator 2 unterschiedliche objekt-typen entgegen nimmt, z.b. vektor und matrix, muss man sich nicht für eine klasse entscheiden, wo die operatoren denn nun definiert werden. wenn es nur eine klasse ist, finde ich die externe lösung auch symetrischer, da beide beteiligten objekte über die parameter referenziert werden und nicht einer über this.
@micki
wegen c-artigen stil: funktionen an sich sind ja nicht c-artiger stil, geschweige denn, dass sie vermieden werden sollten. die unterstützung mehrerer paradigmen (oo, procedural, generisch und teilweise functional) sind ja gerade die stärken von c++ und sollten, wenn sie passen, auch eingesetzt werden. auf java-artigen code, wo alles zwingend irgendwie in eine klasse gestopft werden muss, kann ich unter c++ gut verzichten. wegen dem c-artigen code gebe ich dir natürlich recht, da gibts sicher ganz üble beispiele...
und ich meinte natürlich das buch "more effective c++" vom selben autor, sorry...
vBulletin®, Copyright ©2000-2024, Jelsoft Enterprises Ltd.