PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C++ - Problem mit den Klassen


rotalever
2007-06-08, 22:23:36
Hi,
ich habe ein etwas komplizierteres Problem (zumindest komplizierter zu beschreiben ;) vll. auch weil ich noch C++ Anfänger bin:rolleyes:).

Ich schreibe eine Software, die ich gerne über mehrere Quellcodedateien verteilen möchte, aus denen ich einzeln kompilierte Objektdateien erzeuge, die dann jeweils am Schluss zusammengefügt werden. Warum? Weil man dann während der Entwicklungsphase nicht immer alles neukompilieren muss.

Ich habe mir also gedacht eine Quelldatei pro Klasse zu nehmen. Das einzige Problem ist dabei: Die Klassen sind mehr oder minder von einander Abhängig.

Es gibt zum Beispiel eine Klasse "BASE". Diese hat meinetwegen die private Variable "pvar". Desweiteren habe ich die Klassen "X", "Y". Für ein Objekt von BASE soll es möglich sein, Objekte von X "hinzuzufügen", es werden Pointer in einem Array zu Objekten von X im Objekt von BASE gespeichert. Für ein Object von X soll es möglich sein Objekte von Y "hinzuzufügen", ebenfalls über Pointer gespeichert. Die Objekte selbst sollen vorher unabhängig voneinander erstellt werden können. Also zum Beispiel erst Objekt y, dann base, dann x und dann wird y zu x hinzugefügt und x zu base.

Soweit so gut, in der Klasse BASE habe ich ja wie gesagt die Variable pvar. Sobald ein Objekt von X zu einem von BASE "hinzugefügt" wurde, oder ein Objekt von Y zu einem von X welches wiederum schon BASE hinzugefügt wurde, so soll man von den Objekten von X,Y auf die Variable pvar zugreifen können.

Ich habe mir überlegt, ich definiere X,Y als friends von BASE. Außerdem erhält jedes Objekt aus X und Y einen Pointer zu einem Objekt des Typs BASE. Dieser Pointer wird initialisiert, sobald das Objekt mit einem Objekt von BASE in Verbindung gebracht wurde, d.h. "hinzugefügt" wurde. Dann kann man auf pvar zugreifen.

Ist das so sinnvoll zu realisieren? Oder sollte man einen anderen Ansatz wählen? Wie würde ich das dann mit den angesprochenen mehreren Dateien implementieren können, die ja "unabhängig" sein müssen.

Mfg
rotalever

Silpion
2007-06-09, 00:03:03
Eine Klasse pro Datei (bzw. zwei Dateien, Header und Code) ist vernünftig. Grundsätzlich ist es möglich deine Idee umzusetzen, vermutlich wird es aber schnell unübersichtlich.

Es gibt wahrscheinlich einen eleganteren Weg, aber dazu müsste man wissen, was du umzusetzen versuchst.

del_4901
2007-06-09, 04:00:30
Wenn du einen Cirkelschluss hast ... A includiert B ... B includiert A ... das kann man so nicht machen! Dann muss du das auflösen.

Variante1: neue Klasse C die A und B kennt, und beide miteinander verkuppelt. (Binder Pattern)

Variante2: A erbt von C ... und A includiert B ... B kann dann C includiern.

rotalever
2007-06-09, 10:52:13
Es gibt wahrscheinlich einen eleganteren Weg, aber dazu müsste man wissen, was du umzusetzen versuchst.

Ok vll. Wird es klarer, wenn ich sage, dass es die Klassen base,wmanager,window gibt.
Ein Objekt aus window soll ein Fenster darstellen, logisch. wmanager verwaltet die Fenster ist also ein FensterManager. Zum FensterManager werden Fenster hinzugefügt. Zudem gibt es ein Objekt aus base, zu welchem FensterManager hinzugefügt werden.
Dieses Objekt aus base hat jetzt einige Variablen. Zum Beispiel 100 Pointer zu Bilddaten, die dort in base registriert worden sind und beispielsweise zum Zeichnen aller Fenster aus allen WindowManagers aus dem Objekt von base benötigt werden.


Variante1: neue Klasse C die A und B kennt, und beide miteinander verkuppelt. (Binder Pattern)

Variante2: A erbt von C ... und A includiert B ... B kann dann C includiern.
Das versteh ich leider nicht so ganz wie das gemeint ist, also wie es funktionieren soll.

micki
2007-06-09, 12:20:39
meinst du das so?

#ifndef BASE_HPP
#define BASE_HPP

class CImage;

class CBase
{
CImage* m_pImages[100];
public:
void Add(CWManager* pMan);
const CImage* Image(int i)const;
};

#endif



#ifndef WMANAGER_HPP
#define WMANAGER_HPP

class CWindow;

class CWManager
{
public:
void Add(CWindow* pWindow);
};

#endif



#ifndef WINDOW_HPP
#define WINDOW_HPP

class CWindow
{
};

#endif

wenn ja, wo ist nun genau das problem, so ganz kann ich dir nicht folgen.

rotalever
2007-06-09, 17:29:51
Okay, du machst das hier mit einer public function, die dann soweit ich das verstehe einen Pointer zu dem Image zurückgibt und const ist, damit man das Image nicht ändern kann, oder?

Aber wie werden die einzelnen 3 Dateien dann miteinander verbunden?
Irgendwie so?:
base.hpp : #include manager.hpp, window.hpp
manager.hpp #include base.hpp, window.hpp
window.hpp #include base.hpp
Das versteh ich nicht so ganz.

Gast
2007-06-09, 18:38:59
Solange du nur mit Pointern arbeitest reicht eine Forward Declaration aus. Da braucht man nix zu inkludieren und sollte es auch nicht, wenn man nicht auf lange Compilezeiten steht.

Forward Declaration:
class classname;

Damit weiss der Compiler genug um davon Pointer zu bauen, da alle Objektpointer im Grunde gleich sind.

Inkludieren musst du im Header idr. eigentlich nur bei
- Ableitung von einer Basisklasse: Basisklasse inkludieren
- Membervariablen, die keine Pointer sind -> Typ muss vollständig definiert sein, damit Compiler die Größe kennt
- Templates: können mit den üblichen Compilern nur in den Headern implementiert werden -> alles was man nicht ausschliesslich als Pointer nutzt inkludieren
- Nutzung einer Nested Class/Struct, Enums etc.

Den Rest immer erst in der Implementierungsdatei inkludieren, wenn es wirklich benötigt wird.
Auch oft gesehen hab ich schon Includes von der Friend-Klasse. Ist aber auch überflüssig.

Wo ich Mickis Code grad sehen... pragma once ist zwar nicht Standard C++, aber mir ist noch kein aktueller Compiler übern Weg gelaufen, der es nicht kennt. Dafür ist #pragma once beim Parsen wesentlich schneller als das übliche ifdef Konstrukt, da er direkt aufhört die Datei zu parsen, anstatt das endif zu suchen.

del_4901
2007-06-09, 19:05:37
Okay, du machst das hier mit einer public function, die dann soweit ich das verstehe einen Pointer zu dem Image zurückgibt und const ist, damit man das Image nicht ändern kann, oder?

Aber wie werden die einzelnen 3 Dateien dann miteinander verbunden?
Irgendwie so?:
base.hpp : #include manager.hpp, window.hpp
manager.hpp #include base.hpp, window.hpp
window.hpp #include base.hpp
Das versteh ich nicht so ganz.

So wie du das machen willst bekommst du nen cirkelschluss. Weil der Compiler erst base compelliern kann wenn window fertig ist, und window erst wenn base fertig ist.

micki versucht das oben mithilfe von Prototypen (Vorwärtsdeclaration zu lösen) das geht aber nur, wenn in der hpp wirklich nur der name der Klasse verwendet wird. Das include kann dann in die cpp wandern, und somit können klassen unabhänig voneinander compelliert werden. Sonnst kann man sich nur durch vererbung oder einem Binder helfen. (Einfach mal die Hierarchie aufmalen, wenn es ein Kreis wird: gehts nicht)

rotalever
2007-06-09, 19:12:52
micki versucht das oben mithilfe von Prototypen (Vorwärtsdeclaration zu lösen) das geht aber nur, wenn in der hpp wirklich nur der name der classe verwendet wird. Das include kann dann in die cpp wandern, und somit können klassen unabhänig voneinander compelliert werden. Sonnst kann man sich nur durch vererbung oder einem Binder helfen. (Einfach mal die Hierarchie aufmalen, wenn es ein Kreis wird: gehts nicht)
Ok, das leuchtet mir ein, denn der eigentlich Zugriff auf die public-Funktion ist ja erst in der cpp Datei definiert.
Das mit dem Kreis war ja genau das Problem, wo ich hineingeraten bin..

rotalever
2007-06-09, 20:36:58
Noch was: Wenn ich zum Beispiel einen Fenstermanager bei Base registriere, dann habe ich das Objekt wmo und baseo außerdem eine Funktion in Base, die den Fenstermanager hinzufügt, z.B.

void base::add_wmanager(wmanager * p_wm)
{
/* 1. Irgendwo im baseo speichern, dass er jetzt registriert wurde */
/* 2. wmo (*p_wm) mitteilen, dass es registriert wurde und den Pointer zu baseo ("this") in wmo speichern.*/
}

Nur wie teile ich dem Objekt mit, dass es registriert wurde? Wohl durch eine Funktion. Diese muss aber privat sein, damit der Benutzer sie nicht aufrufen kann. Deshalb müssen die base Klasse ein Freund der wmanager Klasse sein, richtig? Oder denke ich wieder zu kompliziert?

Ok ich habs jetzt, mit dem Friendship scheint das zu funktionieren. Danke für die Tips.