Ich versuche gerade Quellcode aus einer anderen Sprache nach C++ zu
portieren, aus ᅵbungszwecken. Dabei geht es um die Kommunikation
zwischen Objekten. Im speziellen Fall gibt es u.a. eine Klasse Relais
und eine Klasse Taster. Ein oder mehrere Taster _kᅵnnen_ einem Relais
zugeordnet werden, mᅵssen sie aber nicht, dafᅵr hat so ein T. ein Member
vom Typ Relais. So weit so klar. Allerdings ist es so, dass ich
1. abfragen kᅵnnen will, ob der Taster einem Relais zugewiesen wurde
2. nicht weiᅵ, wie ich eine Referenz auf ein Relais an so einen Taster
ᅵbergebe
Hier das vorlᅵufige Beispiel:
#############################
// Taster.h - Deklaration der Tasterklasse
#include "Relais.h"
#ifndef _TASTER_H_
#define _TASTER_H_
class Taster{
private:
Relais relais;
public:
Taster( void );
Taster( Relais akt_relais );
void set_relais( Relais akt_relais );
void push_taster( void );
};
#endif
#############################
#############################
// Taster.cpp - Methoden vom Taster
#include "Taster.h"
#define NULL (void*)0
Taster::Taster( void ){
this->relais = NULL; // eigentlich gibt es NULL in C++ nicht...
}
Taster::Taster( Relais akt_relais ){
this->relais = akt_relais;
}
void Taster::set_relais( Relais akt_relais ){
this->relais = akt_relais;
}
void Taster::push_taster( void ){
if(this->relais != NULL) this->relais.toggle_relais();
}
#############################
Was den zweiten Punkt angeht, so habe ich schon versucht, das Member vom
Typ Relais* zu benutzen, schon allein weil ich dachte, dass der
Compiler dann nicht mehr wegen dem Zeiger auf nix meckern wᅵrde. War ein
Irrtum. Bei der ᅵbergabe als Argument hab ich auch schon (Relais&
akt_relais) versucht, das hat bisher alles nichts gebracht.
Ich fische hier leider momentan im Trᅵben, weil ich merkwᅵrdiger weise
weder in meiner Literatur noch im Netz vernᅵnftige Infos zum Thema zu
finden scheine.
Kann mir hier vielleicht jemand erklᅵren was ich falsch mache?
Gruᅵ Holger
In diesem Fall sagst Du, "Ein Taster besteht aus einem Relais". Das
ist, glaube ich, nicht das, was Du willst. Nach der Beschreibung von
oben willst Du "Ein Taster kennt ein Relais".
C++ behandelt Klassen-Typen nicht anders als int, double, u.s.w. . In
anderen Sprachen (wie zB Java, C# und D) werden solche Klassen-Typen
besonders behandelt. Das, was eine Variable für einen Klassentyp hält
ist nämlich nicht das Objekt selbst, sondern nur eine Referenz.
Du darfst aber nicht die verschiedenen Referenz-Konzepte der Sprachen
durcheinander bringen. Eine C++ Referenz ist wieder etwas ganz
anderes.
Du könntest hier einen Zeiger benutzen und die überflüssigen "void"s
entfernen:
Relais* pr;
public:
Taster();
Taster(Relais*);
void set_relais(Relais*);
void push_taster();
};
> #endif
> #############################
> #############################
> // Taster.cpp - Methoden vom Taster
>
> #include "Taster.h"
> #define NULL (void*)0
>
> Taster::Taster( void ){
> this->relais = NULL; // eigentlich gibt es NULL in C++ nicht...
> }
Taster::Taster() : pr(0) {}
> Taster::Taster( Relais akt_relais ){
> this->relais = akt_relais;
> }
Taster::Taster( Relais* relais )
: pr(relais)
{}
> void Taster::set_relais( Relais akt_relais ){
> this->relais = akt_relais;
> }
void Taster::set_relais( Relais* neu )
{
pr = neu;
}
> void Taster::push_taster( void ){
> if(this->relais != NULL) this->relais.toggle_relais();}
void Taster::push_taster()
{
if (pr) pr->toggle_relais();
}
Du musst beim Portieren etwas aufpassen. Oft lässt sich das Design
nicht 1:1 übersetzen. Das Design, welches in Java noch gut
funktioniert, kann in C++ schlecht sein und umgekehrt. Du weißt, dass
es in C++ keine Garbage Collection gibt, ja? ;-) Das hantieren mit
Zeigern ist immer mit Vorsicht zu genießen. Wenn Du zB Deine Relais in
einem std::vector direkt speicherst, kann nicht garantiert werden,
dass die Elemente immer an der gleichen Stelle im Speicher sitzen (die
gleiche Adresse besitzen), da der vector die Relais eventuell
umkopiert. Dann wären die Relais-Zeiger in den Taster-Objekten
ungültig. Wenn Du allerdings die Relais selbst im Heap anlegst, darfst
Du nicht vergessen, sie wieder zu löschen.
Gruß,
SG
> Hier das vorlᅵufige Beispiel:
>
> #############################
> // Taster.h - Deklaration der Tasterklasse
>
> #include "Relais.h"
>
> #ifndef _TASTER_H_
> #define _TASTER_H_
>
> class Taster{
> private:
> Relais relais;
Relais* relais;
>
> public:
> Taster( void );
> Taster( Relais akt_relais );
Taster( Relais* akt_relais );
>
> void set_relais( Relais akt_relais );
void set_relais( Relais* akt_relais );
> void push_taster( void );
> };
>
> #endif
> #############################
> #############################
> // Taster.cpp - Methoden vom Taster
>
> #include "Taster.h"
> #define NULL (void*)0
NULL braucht kein Mensch ;)
>
> Taster::Taster( void ){
> this->relais = NULL; // eigentlich gibt es NULL in C++ nicht...
relais = 0; // this ist ᅵberflᅵssig und 0 ist das was du suchst
> }
>
> Taster::Taster( Relais akt_relais ){
Taster::Taster( Relais* akt_relais ){
> this->relais = akt_relais;
relais = akt_relais;
> }
>
> void Taster::set_relais( Relais akt_relais ){
void Taster::set_relais( Relais* akt_relais ){
> this->relais = akt_relais;
relais = akt_relais;
> }
>
> void Taster::push_taster( void ){
> if(this->relais != NULL) this->relais.toggle_relais();
if(relais != 0) relais->toggle_relais();
> }
Zeiger sind schon richtig, NULL brauchst du nicht, 0 ist das was du
suchst. Du musst aber darauf achten, dass dein Relais auch solange lebt
wie der Taster (falls du Java oder etwas ᅵhnliches mit garbage
collection gemacht hast: das ist in C++ anders!).
Lars
Dir fehlt ja schon einmal die Zuordnungsmᅵglichkeit mehrerer Relais zu
einem Taster. Hierfᅵr bieten sich die STL Container an. Gᅵngig ist da
std::vector, in diesem speziellen Fall wᅵrde ich ein std::set nehmen,
damit vermeidet man, dass einem Taster dasselbe Relais mehrfach
zugeordnet wird. Nachfolgend ein Beispiel, wie man es machen kᅵnnte. Der
Quellcode ist per cut and paste bei www.codepad.org ausfᅵhrbar (deshalb
das Gemenge aus .h und .cpp)
-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
#include <string>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;
class Relais
{
public:
Relais(char const * name) : name_(name) {}
void toggle() {cout << "toggle " << name_ << endl;}
private:
string name_;
};
class Taster
{
set<Relais *> relais_;
public:
Taster();
Taster(Relais * relais) {add_relais(relais);}
void add_relais(Relais * relais) {relais_.insert(relais);}
void push_taster() {for_each(relais_.begin(), relais_.end(),
mem_fun(&Relais::toggle));}
};
int main()
{
Relais relais1("R1");
Relais relais2("R2");
Taster taster1(&relais1);
taster1.add_relais(&relais2);
taster1.push_taster();
}
-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
Ciao
Jens
Schon richtig was du brauchts ist ein Pointer auf Relais.
Denn nur ein Pointer kann 0 bzw. NULL werden.
Es gibt auch andere Mᅵglichkeiten das zu erreichen z.B. eine
Null-Relais-Object aber Pointer ist einfacher.
> class Taster{
> private:
> Relais relais;
Relais* relais;
> Taster::Taster( void ){
> this->relais = NULL; // eigentlich gibt es NULL in C++ nicht...
> }
Das ginge zwar. Aber so ist es hᅵbscher:
Taster::Taster() : relais(NULL) {};
Initialisierung statt Zuweisung. Und "void" ist ᅵberflᅵsig.
> Taster::Taster( Relais akt_relais ){
> this->relais = akt_relais;
Das ist falsch.
Richtig wᅵre:
//als Referenz ᅵbergeben (geht)
Taster::Taster(const Relais& akt_relais) : relais(&akt_relais) {}
//direkt als Pointer ᅵbergeben (besser)
Taster::Taster(const Relais* akt_relais) : relais(akt_relais) {}
Deine Variante erzeugt eine Kopie (call by value) eines Relais. Und der
Zeiger zeigt dann auf andere Adresse. Und das neue Object akt_relais
lebt auch nur bis zum Ende der Funktion offziell. Es wird danach ungᅵltig.
Wenn du keine nackigen Pointer willst, dann kannst du sie auch in einen
Smartpointer verpacken auto_ptr und co.
> Ich versuche gerade Quellcode aus einer anderen Sprache nach C++ zu
> portieren, aus ᅵbungszwecken. Dabei geht es um die Kommunikation
> zwischen Objekten. Im speziellen Fall gibt es u.a. eine Klasse Relais
> und eine Klasse Taster. Ein oder mehrere Taster _kᅵnnen_ einem Relais
> zugeordnet werden, mᅵssen sie aber nicht, dafᅵr hat so ein T. ein Member
> vom Typ Relais. So weit so klar. Allerdings ist es so, dass ich
Beliebige Anzahl kannst du dann mit std::vector<Relais> relais; realisieren.
> 1. abfragen kᅵnnen will, ob der Taster einem Relais zugewiesen wurde
return relais.empty();
> 2. nicht weiᅵ, wie ich eine Referenz auf ein Relais an so einen Taster
> ᅵbergebe
Z.b. eine konstante Referenz kannst du mit
void Taster::f(Relais const& r)
{}
ᅵbergeben. Das kannst du dann einfᅵgen (push_back), so wie ich relais oben
definiert habe, wird es dann kopiert.
> class Taster{
> private:
Ist automatisch private, kannst du aber wg. ᅵbersichtlichkeit o.ᅵ. natᅵrlich
angeben.
> Relais relais;
Damit realisierst du ja eine 1:1 Beziehung, s.o.
> public:
> Taster( void );
( void ) muss in C++ auch nicht mehr angegeben werden, das ist automatisch
so.
> Taster( Relais akt_relais );
Bei dieser ᅵbergabe wᅵrde kopiert werden.
> #define NULL (void*)0
Setze es lieber nicht.
> Taster::Taster( void ){
> this->relais = NULL; // eigentlich gibt es NULL in C++ nicht...
Und verwende es auch lieber nicht, siehe FAQ.
NULL gibt es allerdings schon. Es kann aber immer 0 stattessen verwendet
werden (gilt aber nicht umgekehrt).
> Ich fische hier leider momentan im Trᅵben, weil ich merkwᅵrdiger weise
> weder in meiner Literatur noch im Netz vernᅵnftige Infos zum Thema zu
> finden scheine.
>
> Kann mir hier vielleicht jemand erklᅵren was ich falsch mache?
Du wirst kein Spaᅵ daran haben, wenn du dir kein Buch zulegst und die
Grundlagen lernst.
mfg Markus
> Ich versuche gerade Quellcode aus einer anderen Sprache nach C++ zu
> portieren, aus Übungszwecken. Dabei geht es um die Kommunikation
> zwischen Objekten. Im speziellen Fall gibt es u.a. eine Klasse Relais
> und eine Klasse Taster. Ein oder mehrere Taster _können_ einem Relais
> zugeordnet werden, müssen sie aber nicht, dafür hat so ein T. ein Member
> vom Typ Relais. So weit so klar.
Nein. Eine Zuordnung ist nicht ein "Enthalten". Wenn die Zuordnung fest
ist, dann benutzt Du eine Referenz, wenn sie geändert werden kann, einen
Zeiger.
> Allerdings ist es so, dass ich
>
> 1. abfragen können will, ob der Taster einem Relais zugewiesen wurde
Damit muss es ein Zeiger sein.
> 2. nicht weiß, wie ich eine Referenz auf ein Relais an so einen Taster
> übergebe
Zeiger, nicht Referenz. Der Parameter wird so deklariert, wie die
entsprechende Variable.
> Hier das vorläufige Beispiel:
>
> #############################
> // Taster.h - Deklaration der Tasterklasse
>
> #include "Relais.h"
Taster.h verwendet kein Wissen aus Relais.h, ausser dass Relais eine
Klasse ist. Damit ist es oft besser, nur genau dies hinzuschreiben.
> #ifndef _TASTER_H_
> #define _TASTER_H_
>
> class Taster{
> private:
> Relais relais;
Nicht einfügen, sondern ein Zeiger.
> public:
> Taster( void );
> Taster( Relais akt_relais );
>
> void set_relais( Relais akt_relais );
> void push_taster( void );
> };
>
> #endif
> #############################
> #############################
> // Taster.cpp - Methoden vom Taster
Genitiv, nicht Dativ.
> #include "Taster.h"
Hier dann wirklich "Relais.h" einfügen.
> #define NULL (void*)0
NULL ist in C++ wegen des nicht automatischen Cast nicht sinnvoll.
> Taster::Taster( void ){
> this->relais = NULL; // eigentlich gibt es NULL in C++ nicht...
"this->" ist für alle Member innerhalb der Methoden implizit, also
weglassen.
Kommentare zum Sprachverständnis sollten auf die Fälle beschränkt
werden, die wirklich obskure Eigenschaften der Sprache verwenden.
> }
[Keine neuen Anmerkungen über den Rest.]
> #############################
>
> Was den zweiten Punkt angeht, so habe ich schon versucht, das Member vom
> Typ Relais* zu benutzen, schon allein weil ich dachte, dass der
> Compiler dann nicht mehr wegen dem Zeiger auf nix meckern würde. War ein
> Irrtum.
Aber die richtige Richtung. Du hast nur einen großen Denkfehler (kein
Zeiger) durch einen kleinen (keine automatische Konvertierung von void*)
ersetzt. Das konnte der Compiler nicht erkennen. Du hättest allerdings mal
die Fehlermeldung Deines Compilers in die Anfrage aufnehmen können.
> Bei der Übergabe als Argument hab ich auch schon (Relais&
> akt_relais) versucht, das hat bisher alles nichts gebracht.
Relais& ist immer eine gültige Referenz. Das willst Du ja gerade nicht.
> Ich fische hier leider momentan im Trüben, weil ich merkwürdiger weise
> weder in meiner Literatur noch im Netz vernünftige Infos zum Thema zu
> finden scheine.
>
> Kann mir hier vielleicht jemand erklären was ich falsch mache?
Da Du anscheinend an Grundlagen scheiterst, hier mal ein vollständiges,
fehlerfrei übersetzbares Beispiel:
#############################
// Relais.hh - triviale Variante
class Relais
{
public:
void toggle_relais (void);
};
#############################
// Taster.h - Deklaration der Tasterklasse
#ifndef _TASTER_H_
#define _TASTER_H_
class Relais;
class Taster{
private:
Relais *relais;
public:
Taster( void );
Taster( Relais *akt_relais );
void set_relais( Relais *akt_relais );
void push_taster( void );
};
#endif
#############################
// Taster.cpp - Methoden des Tasters
#include "Taster.h"
#include "Relais.h"
Taster::Taster( void ){
relais = 0;
}
Taster::Taster( Relais *akt_relais ){
relais = akt_relais;
}
void Taster::set_relais( Relais *akt_relais ){
relais = akt_relais;
}
void Taster::push_taster( void ){
if (relais) relais->toggle_relais();
}
#############################
--
Viele Grüße,
Jens Schmidt
Holger Jorra schrieb:
> Ich versuche gerade Quellcode aus einer anderen Sprache nach C++ zu
> portieren, aus ᅵbungszwecken.
Wird den an den Schulen nur noch Java gelehrt? ;-)
> Dabei geht es um die Kommunikation
> zwischen Objekten. Im speziellen Fall gibt es u.a. eine Klasse Relais
> und eine Klasse Taster. Ein oder mehrere Taster _kᅵnnen_ einem Relais
> zugeordnet werden, mᅵssen sie aber nicht, dafᅵr hat so ein T. ein Member
> vom Typ Relais. So weit so klar. Allerdings ist es so, dass ich
Diese Optionalitᅵt kann man verschiedends ausdrᅵcken. Ein Zeiger ist
eine Mᅵglichkeit. Was am besten geeingnet ist, geht aus Deiner
Beschreibung nicht hervor. Wenn wir jetzt also einen Zeiger nehmen, dann
muss aber auch klar sein, dass es sich hier um eine Assoziation, nicht
um eine Komposition handelt. Sprich der Taster verweist auf das Relais,
es geht ihm aber nicht.
> 1. abfragen kᅵnnen will, ob der Taster einem Relais zugewiesen wurde
> 2. nicht weiᅵ, wie ich eine Referenz auf ein Relais an so einen Taster
> ᅵbergebe
>
> Hier das vorlᅵufige Beispiel:
>
> #############################
> // Taster.h - Deklaration der Tasterklasse
>
>
> #ifndef _TASTER_H_
> #define _TASTER_H_
Bezeichner mit einem Unterstrich gefolgt von einem Buchstaben gehᅵren
dem Compiler und sollten nicht verwendet werden.
class Relaise;
> class Taster{
> private:
Relais* relais;
>
> public:
> Taster();
Taster( Relais& akt_relais );
>
void set_relais( Relais& akt_relais );
> void push_taster();
> };
>
> #endif
> #############################
> #############################
> // Taster.cpp - Methoden vom Taster
>
> #include "Taster.h"
>
> Taster::Taster(){
: relais(0)
{
> }
>
> Taster::Taster( Relais& akt_relais ){
: relais(&akt_relais)
> }
>
> void Taster::set_relais( Relais& akt_relais ){
relais = &akt_relais;
> }
>
> void Taster::push_taster(){
> if( relais != 0 ) relais->toggle_relais();
> }
> #############################
>
> Was den zweiten Punkt angeht, so habe ich schon versucht, das Member vom
> Typ Relais* zu benutzen, schon allein weil ich dachte, dass der
> Compiler dann nicht mehr wegen dem Zeiger auf nix meckern wᅵrde. War ein
> Irrtum. Bei der ᅵbergabe als Argument hab ich auch schon (Relais&
> akt_relais) versucht, das hat bisher alles nichts gebracht.
Ihn C++ gibt es den Unterschied zwischen Wert und Referenz.
Relais relais; relais ist eine Variable vom Typen Relaise
Relais& ref = relais; ref ist ein Referenz, die auf das Objekt relaise
referenziert.
Relais* p = &ref; ist ein Zeiger, der auf das Objekt relais zeigt.
> Ich fische hier leider momentan im Trᅵben, weil ich merkwᅵrdiger weise
> weder in meiner Literatur noch im Netz vernᅵnftige Infos zum Thema zu
> finden scheine.
Dann schmeiᅵ die Literatur weg, das sind wirklich ganz grundsᅵtzliche
Sachen ;-)
> Kann mir hier vielleicht jemand erklᅵren was ich falsch mache?
Wahrscheinlich die falschen Bᅵcher lesen.
mfg Torsten
--
kostenlose Wirtschaftssimulation: http://www.financial-rumors.de
> Ich versuche gerade Quellcode aus einer anderen Sprache nach
> C++ zu portieren, aus Übungszwecken. Dabei geht es um die
> Kommunikation zwischen Objekten. Im speziellen Fall gibt es
> u.a. eine Klasse Relais und eine Klasse Taster. Ein oder
> mehrere Taster _können_ einem Relais zugeordnet werden, müssen
> sie aber nicht, dafür hat so ein T. ein Member vom Typ Relais.
> So weit so klar. Allerdings ist es so, dass ich
>
> 1. abfragen können will, ob der Taster einem Relais zugewiesen
> wurde
> 2. nicht weiß, wie ich eine Referenz auf ein Relais an so
> einen Taster übergebe
Erste Frage: ist die Navigation unidirektionnell, oder nicht?
D.h.: geht man immer von Taster nach Relais, oder muss man auch
von Relais nach den Taster gehen können?
> Hier das vorläufige Beispiel:
> #############################
> // Taster.h - Deklaration der Tasterklasse
> #include "Relais.h"
> #ifndef _TASTER_H_
> #define _TASTER_H_
>
> class Taster{
> private:
> Relais relais;
Hier brauchst du einen Zeiger; der Relais soll nicht einen
Bestandteil des Taster sein. Also:
Relais* relais ;
> public:
> Taster( void );
> Taster( Relais akt_relais );
Und hier auch. Ich würde einfach nur ein einzigen Constructor
vereinbaren:
Taster( Relais* akt_relais = NULL ) ;
> void set_relais( Relais akt_relais );
> void push_taster( void );
> };
> #endif
> #############################
> #############################
> // Taster.cpp - Methoden vom Taster
> #include "Taster.h"
> #define NULL (void*)0
DAS darfst du nicht. NULL ist schon in C++ definiert (in Header
<cstdlib> bzw. <stdlib.h>), und soll nicht anders definiert
sein. Also, hier:
#include <stdlib.h>
> Taster::Taster( void ){
> this->relais = NULL; // eigentlich gibt es NULL in C++ nicht...
Doch. In <stdlib.h>, genau so wie in C. Dazu würde ich eine
"Initialization-List" benutzen, also:
Taster::Taster(
Relais* akt_relais )
: relais( akt_relais )
{
}
(Mit dem default-Parameter brauchst du keinen anderen
Constructor.)
Wenn der Relais auch wissen muss, dass dieser Taster ihn
zugewiesen ist, musst du ihm dazu mitteilen.
> }
> Taster::Taster( Relais akt_relais ){
> this->relais = akt_relais;
Die ganzen this-> sind überflüssig, und dazu etwas ungewöhnlich.
> }
> void Taster::set_relais( Relais akt_relais ){
> this->relais = akt_relais;
> }
> void Taster::push_taster( void ){
> if(this->relais != NULL) this->relais.toggle_relais();
if ( relais != NULL ) {
relais->toggle_relais() ;
}
> }
> #############################
> Was den zweiten Punkt angeht, so habe ich schon versucht, das
> Member vom Typ Relais* zu benutzen, schon allein weil ich
> dachte, dass der Compiler dann nicht mehr wegen dem Zeiger auf
> nix meckern würde.
Relais* muss es wohl sein, wenn das Objekt selbst nicht in der
Klasse stehen soll.
> War ein Irrtum. Bei der Übergabe als Argument hab ich auch
> schon (Relais& akt_relais) versucht, das hat bisher alles
> nichts gebracht.
Es gibt drei unterschiedene Sachen: Zeiger, Referenzen und das
Objekt selbe. Syntactisch betrachtet behalten sich Referenzen
eher wie Objekte; man könnte sie als alternative Namens des
Objektes. Zeiger, dagegen, sind sich selber Objekte (mit einem
Zeigertyp); wenn du ein Objekt (oder eine Referenz) hast, und
einen Zeiger brauchst, dann muss du es "konvertieren", mittels
&. Also:
Taster::Taster( Relais& akt_relais )
: relais( &ack_relais )
{
}
Nur haben Referenzen einige Beschränkungen---sie können nicht
NULL sein, und sie können nicht geändert werden, einmal, dass
sie eingerichtet sind. Also als Dataelement von Taster muss du
einen Zeiger verwenden. Ich würde ihn auch als Parameter
verwenden (und verlangen, dass den Aufrufenden & benutzt); wenn
du aber Referenzen als Parameter benutzen will, dann brauchst du
wohl zwei Constructore (weil du keine null-Referenz als
default-Parameter benutzen kannst):
Taster::Taster()
: relais( NULL )
{
}
Taster::Taster(
Relais& ack_relais )
: relais( &ack_relais )
{
}
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> Beliebige Anzahl kannst du dann mit std::vector<Relais>
> relais; realisieren.
Das würde ich in jedem Fall vermeiden. Es wird von Taster nach
Relais navigiert. Das heißt, dass es Zeiger auf Relais gibt, und
also höchstwahrscheinlich, dass Relais nicht kopierbar ist. (Es
gibt wohl Ausnahme, aber in allgemeinem Fall gilt es, dass
Objekt, auf dem du zeigen kannst, Identität besitzen, und nicht
kopiert werden darf.)
> > 1. abfragen können will, ob der Taster einem Relais
> > zugewiesen wurde
> return relais.empty();
return relais != NULL ;
Ansonsten musst du suchen, ob der gegebenen Relais in der
Tabelle ist oder nicht.
> > 2. nicht weiß, wie ich eine Referenz auf ein Relais an so
> > einen Taster übergebe
> Z.b. eine konstante Referenz kannst du mit
> void Taster::f(Relais const& r)
> {}
> übergeben. Das kannst du dann einfügen (push_back), so wie ich
> relais oben definiert habe, wird es dann kopiert.
Genau das Kopieren soll man vermeiden.
> > class Taster{
> > private:
> Ist automatisch private, kannst du aber wg. Übersichtlichkeit
> o.ä. natürlich angeben.
> > Relais relais;
> Damit realisierst du ja eine 1:1 Beziehung, s.o.
Nein. Damit realisiert er keine Beziehung. Das Objekt relais
selbe gehört damit zu Taster, und existiert sogar nicht außer
Taster.
> > public:
> > Taster( void );
> ( void ) muss in C++ auch nicht mehr angegeben werden, das ist
> automatisch so.
> > Taster( Relais akt_relais );
> Bei dieser Übergabe würde kopiert werden.
> > #define NULL (void*)0
> Setze es lieber nicht.
Besonders weil es verboten ist.
> > Taster::Taster( void ){
> > this->relais = NULL; // eigentlich gibt es NULL in C++ nicht...
> Und verwende es auch lieber nicht, siehe FAQ.
Es gibt kein Problem, NULL zu benutzen. (Ich finde auch nichts
in der FAQ, das anders sagt.)
> > 1. abfragen können will, ob der Taster einem Relais
> > zugewiesen wurde
> > 2. nicht weiß, wie ich eine Referenz auf ein Relais an so
> > einen Taster übergebe
> > Hier das vorläufige Beispiel:
> [...]
> Dir fehlt ja schon einmal die Zuordnungsmöglichkeit mehrerer
> Relais zu einem Taster.
Das hat er nicht verlangt. Wie er es beschrieben hat, ist die
Beziehung Taster->Relais 1->{0,1}, was am einfachsten durch
einen Zeiger implementiert wird.
Anderseits ist die Beziehung Relais->Taster 1->n. Vorläufig hat
er aber nicht gesagt, dass diese Beziehung navigierbar muss.
Falls dass der Fall wird, dann wird der Code etwas
komplizierter, weil er muss versichern, dass die Beziehungen
gegenseitig übereinstimmen.
> Hierfür bieten sich die STL Container an. Gängig ist da
> std::vector, in diesem speziellen Fall würde ich ein std::set
> nehmen, damit vermeidet man, dass einem Taster dasselbe Relais
> mehrfach zugeordnet wird.
Es kommt an die Anforderung an. Ich würde wohl mit
std::vector<Taster*> bleiben, ggf. mit:
assert( std::find( myTaster.begin(), myTaster.end(), neuerTaster )
== myTaster.end() ) ;
vor dem Zufügen. Das Hauptproblem aber bleibt: jedesmal, dass
der Relais in Taster geändert wird, muss auch die entsprechende
Tabelle in Relais aktualisiert.
> Wird den an den Schulen nur noch Java gelehrt? ;-)
An den Schulen wᅵre es ja ok.
Aber z.B. in meiner Firma gilt Java als das Nonplusultra an
Programmiersprache. So sehr das es kaum was anderes gibt.
Fragen nach einer API fᅵr 3rd Party Software, werden so formuliert, ob
es da auch eine "Java-API" gᅵbe. Ersthaft.
Und besser als Java ist nur noch BPEL...
Vielen Dank fᅵr die vielen hilfreichen Antworten. Ich hab tatsᅵchlich
erst dadurch gemerkt, was bei mir der (grundlegende) Fehler war: Ich hab
Referenzen mit Zeigern verwechselt. Wirklich peinlich.
Nachdem ich das korrigiert habe, lᅵuft das Progrᅵmmchen nun einwandfrei.
(void*)0 hab ich natᅵrlich jetzt auch entsorgen kᅵnnen.
Also danke nochmal
Holger
Es hat fᅵr mich nach einer Aggregation ("is-part-of") Beziehung ausgesehen,
die er in dem ursprᅵnglichen Beispiel ja auch hatte. Aber ist ja egal, dem
Op wurde bereits geholfen.
>> Damit realisierst du ja eine 1:1 Beziehung, s.o.
>
> Nein. Damit realisiert er keine Beziehung. Das Objekt relais
> selbe gehᅵrt damit zu Taster, und existiert sogar nicht auᅵer
> Taster.
Ich glaube nicht das eine Begriffsklauberei hier weiterhilft (ob
jetzt "is-part-of" eine Aggregation und diese eine Beziehung ist oder
nicht).
>> > #define NULL (void*)0
>
>> Setze es lieber nicht.
>
> Besonders weil es verboten ist.
Ja :-)
>> > Taster::Taster( void ){
>> > this->relais = NULL; // eigentlich gibt es NULL in C++ nicht...
>
>> Und verwende es auch lieber nicht, siehe FAQ.
>
> Es gibt kein Problem, NULL zu benutzen. (Ich finde auch nichts
> in der FAQ, das anders sagt.)
Es steht nirgends so eindeutig da es (in obiger Situation) letztlich
Stilfrage ist, aber z.b.: http://www.research.att.com/~bs/bs_faq2.html#null
Ein Problem ist z.b. welche Methode aufgerufen wird, wenn es:
void func (int i);
void func (void *i);
gibt. Das Problem wird aber sowieso erst richtig durch die Verwendung von
nullptr behoben.
Eindeutig falsch ist die Verwendung von NULL z.b. um eine Methode rein
abstrakt zu machen. Und ja, ich habe das schon wo gesehen.
mfg Markus
> > Nein. Damit realisiert er keine Beziehung. Das Objekt relais
> > selbe gehört damit zu Taster, und existiert sogar nicht außer
> > Taster.
> Ich glaube nicht das eine Begriffsklauberei hier weiterhilft
> (ob jetzt "is-part-of" eine Aggregation und diese eine
> Beziehung ist oder nicht).
Das will ich auch nicht. Besonders weil als nicht
Muttersprachler kann ich nur verlieren. Aus der ursprünglichen
Beschreibung hatte ich abgeschlossen (möglicherweise
irrtümlich), dass der Poster eine »Association« wollte, und
nicht ein »Attribute« (um das Vokabular von UML zu benutzen);
dazu habe ich (vielleicht fehlerhaft) »Beziehung« als
»Association« verstanden.
[...]
> >> > Taster::Taster( void ){
> >> > this->relais = NULL; // eigentlich gibt es NULL in C++ nicht...
> >> Und verwende es auch lieber nicht, siehe FAQ.
> > Es gibt kein Problem, NULL zu benutzen. (Ich finde auch
> > nichts in der FAQ, das anders sagt.)
> Es steht nirgends so eindeutig da es (in obiger Situation)
> letztlich Stilfrage ist,
In der Tat. Es gibt zwei Denkweise. Ich gehöre zu denen, die
NULL benutzen.
> aber
> z.b.:http://www.research.att.com/~bs/bs_faq2.html#null
> Ein Problem ist z.b. welche Methode aufgerufen wird, wenn es:
> void func (int i);
> void func (void *i);
> gibt. Das Problem wird aber sowieso erst richtig durch die
> Verwendung von nullptr behoben.
Genau. Es gibt ein gründsetzliches Problem, ohne richtige
Lösung. Egal was man tut, es ist nicht optimal. Man will, sogar
soll, darauf hinweisen, dass es um einen Zeiger geht. Also NULL.
Anderseits besteht das Problem, dass du zeigst. Bei Überladenen
Funktionen könnte ich argumentieren, dass es soll egal sein,
welche aufgerufen wird; amsonsten sollen sie unterschiedene
Namen haben. Bei Konstruktoren bzw. Funktionstemplate aber ist
es nicht so eindeutig; endlich kann man nicht Konstruktoren
unterschiedene Namen geben.
In Allgemein denke ich, dass Leute die relativ wenig überladen,
mit nicht zu vielen Templates (also, wie ich), NULL bevorziehen;
Leute, die viel überladen, und alles mit Templates erledigen, 0.
Ich würde aber nicht "verwende es lieber nicht" sagen, egal
welche Wahl der Programmierer getroffen hat.
> Eindeutig falsch ist die Verwendung von NULL z.b. um eine
> Methode rein abstrakt zu machen. Und ja, ich habe das schon wo
> gesehen.
Und rein formell ist es auch erlaubt:-). (Oder nicht. NULL can
auch etwas wie "(1-1)" sein, was nicht für abstrakte Funktionen
geht.) In jedem Fall bin ich mit dir einverstanden; solche
Benutzung ist eindeutig falsch (da es nicht um einen Zeiger
geht). Auch habe ich NULL für '\0', oder ein Integer 0 gesehen,
was ich auch als falsch betrachte.
Entschuldigt bitte, wenn ich diesen Thread noch einmal wiederbelebe, aber
hier taucht noch eine interessante Frage auf.
Ich meine, dass das nur zul�ssig ist, wenn alle in einer Instanz des
std::set verwendeten Pointer aus einem zusammenh�ngenden Speicherblock
stammen, weil nur dann die Vergleichsoperation definiert ist. Da das wohl
kaum der Fall sein wird, ist es also im allgemeinen fehlerhafter Code,
andererseits wird es auf nahezu jedem realen System funktionieren.
Andere Meinungen oder irgend eine Ausnahmeregelung, die das doch f�r
zul�ssig erkl�rt?
ciao
Lutz
Die Ausnahmeregelung ist, dass std::set als Vergleichsoperation
std::less benutzt, welches f�r Zeigertypen wohldefiniert eine totale
Ordnung liefert. Auf standardesisch in 20.3.3p8:
| For templates greater, less, greater_equal, and less_equal, the
| specializations for any pointer type yield a total order, even if the
| builtin operators <, >, <=, >= do not.
Stefan
> Die Ausnahmeregelung ist, dass std::set als Vergleichsoperation
> std::less benutzt, welches f�r Zeigertypen wohldefiniert eine totale
> Ordnung liefert. Auf standardesisch in 20.3.3p8:
>| For templates greater, less, greater_equal, and less_equal, the
>| specializations for any pointer type yield a total order, even if the
>| builtin operators <, >, <=, >= do not.
Danke, dann bin ich ja beruhigt.
Lutz