Vererbung und Listen

thekiller

Viceinator
Hallo Tag,

ich hab gerade nen kleines Problem wo ich nicht weiß wie ich es in C++ lösen soll. Vielleicht könnt Ihr mir da ja helfen.

Also ich versuchs mal anhand eines Menüs zu erklären.

Stellt euch eine Klasse vor, ich nenn sie mal Basis-Klasse, die für sämtliche Menüelemente die Basis bildet und natürlich bestimmte Grundeigenschaften wie Position, Breite, Höhe etc. hat. Halt alles so Eigenschaften die für alle Menüelemente wichtig sind und gebraucht werden.

Also jedes Element erbt von der Basis-Klasse. Nun habe ich eine abgeleitete Klasse welches ein Widget sein soll. Dieses Widget soll eine Liste enthalten mit allen Elementen die diesem Widget zugeordnet sind also Labels, Buttons, Checkboxen, Groupboxen, andere Widgets und so weiter.
So dass man halt gut Verschachteln kann. Ich hoffe Ihr versteht was ich meine.

Kann man sowas in einer Liste realisieren oder muss man für jede Sorte eine eigene Liste anlegen.

MfG Manuel
 
Ja, das geht grundsätzlich schon, du musst für alle diese Komponenten wie Checkbox, Label, Button usw eine Basisklasse entwerfen (z.B. Control) und die dann implementieren. Dann kann dein Widget einfach eine Liste von Controls haben und dann entweder mit einer abstrakten Methode, welche den Type des Elements zurückgibt oder via dynamic_cast falls nötig spezialisierte Aufrufe machen. Aus meiner Erfahrung reicht es jedoch mit einer intelligent definierten Control-Klasse völlig aus in einem Widget, dieses benötigt keine Information darüber, was für Elemente sie hat.
 
Hallo

Simpel gesagt folgendermassen:
C++:
class Control
{
public:
   virtual void Hide() = 0;
   virtual void SetPosition(uint32 x, uint32 y) = 0;
   //...
};

class Button : public Control
{
public:
   void Hide() { visible = false; }
   void SetPosition(uint32 x, uint32 y) { pos.x = x; pos.y = y; }
};

class Widget
{
   std::list<Control*> mControls;
public:
   void AddControl(Control* pControl)
   {
      mControls.push_back(pControl);
   }
   
   void Disable()
   {
      for(std::list<Control*>::iterator itr = mControls.begin(); itr != end; ++itr)
      {
         (*itr)->Hide();
      }
   }
};

Widget myWidget;
Button myButton;
myButton.SetPosition(20, 20);
myWidget.AddControl(&myButton);
 
Moin ch hab nochmal ne Frage dazu.

Habe ich ein Speicherleck bei folgendem Code?

C++:
class	Base {
	public:
		Base() {}
		~Base() {
		}
};

class	Widget : public Base {
	private:
		int	Var;
		
	public:
		Widget () {}
		~Widget () {
		}
};

int main() {
	Widget	*hWidget	= new Widget;
	Base	*Temp		= hWidget;
	
	delete	Temp;	// Bekomm ich hier ein Speicherleck****?
}

EDIT.: Kleinen Hektikfehler im Code behoben. Konstruktor und Destruktor von Widget sollten natürlich auch Widget heißen^^
 
Zuletzt bearbeitet von einem Moderator:
In diesem speziellen Fall nicht (ich schätze einfach mal, dass Konstruktor und Destruktor in Widget eigentlich auch so heissen und nicht Base), aber z.B. in folgendem:
C++:
class   Base {
    public:
        Base() {}
        ~Base() {
        }
};

class   Foo {
	int* someMemory;
public:
	Foo() {
		someMemory = new int;
	}

	~Foo() {
		delete someMemory;
	}
};
 
class   Widget : public Base {
    private:
        int Var;
	Foo foo;
        
    public:
        Widget() {}
        ~Widget() {
        }
};
 
int main() {
    Widget  *hWidget    = new Widget;
    Base    *Temp       = hWidget;
    
    delete  Temp;   // Bekomm ich hier ein Speicherleck****?
}
Grund dafür ist, dass lediglich der Destruktor von Base aufgerufen wird, nicht jedoch der von Widget, somit wird auch der Destruktor von Foo nicht aufgerufen und der allozierte Speicher nicht befreit. Lösung dafür ist ein virtueller Destruktor der Basisklasse:
C++:
class   Base {
    public:
        Base() {}
        virtual ~Base() {
        }
};

class   Foo {
	int* someMemory;
public:
	Foo() {
		someMemory = new int;
	}

	~Foo() {
		delete someMemory;
	}
};
 
class   Widget : public Base {
    private:
        int Var;
	Foo foo;
        
    public:
        Widget() {}
        ~Widget() {
        }
};
 
int main() {
    Widget  *hWidget    = new Widget;
    Base    *Temp       = hWidget;
    
    delete  Temp;   // Bekomm ich hier ein Speicherleck****?
}

Damit wird der Destruktor von Base auf Assemblerebene bisschen umgestaltet und es wird zusätzlich ein Slot in der VMT reserviert in den die Adresse des zu dieser Instanz passenden zusätzlichen Destruktors der Kindklasse kommt. Somit wird also dann auch beim Aufruf von Base::~Base in diesem Fall Widget::~Widget aufgerufen.
 
Konstruktor und Destruktor von Widget sollten natürlich auch Widget heißen sry. Copy&Paste error^^

Also ist es sinnvoll den Destruktor der Basisklasse immer virtual zu deklarieren?
 
Zurück