[C#] Allgemeine Programmier Fragen

Magic1416

Lieutenant
Registriert
Dez. 2003
Beiträge
533
Hallo Zusammen,

ich beschäftige mich seit einiger Zeit mit C# und arbeite dazu ein ca. 1000 seitiges Buch ab. Leider gibt mir das Buch auf bestimmte Fragen keine Antwort.

Es wird sehr viel erklärt, was ich machen und vorallem wie ich es mache und anhand von Beispielen erklärt. Das ist nicht schlecht.

Jedoch fehlt mir manchmal die Erklärung, warum das ein oder andere überhaupt brauche.

Z.B.

Structs und Classes.
Beide sind vom Code her identisch. Structs speichern die Verweise im Stack. Classes ihre im Heap. Schön dass das so ist. Welchen Vorteil hab ich davon, etwas im Heap oder im Stack zu speichern ?

Desweiteren kann ich mit einer Klasse genau dasselbe bzw. mehr als mit einem Struct realisieren. Wozu dann noch das Struct ?

Da komm ich schon zu dem nächsten Punkt. Klassen ableiten, Vererbung und Interfaces. In diesem zusammenhang gibt es dann die Möglichkeit, Methoden zu überschreiben, indem ich denselben Namen mehrmals verwende und mit den Schlüsselwörtern Virtual und override arbeite. Kann mir jemand ein Beispiel nennen wo das Sinn machen soll, den Namen einer Methode mehrfach zu verwenden ?

Interfaces hab ich in dem Zusammenhang überhaupt nicht verstanden. Laut Buch sollen Sie die Handhabung wohl vereinfachen. Allerdings, wenn ich versuche ein Interface zu verwenden hab ich im Visual Studio keine Auswahl an Methoden oder sonstigen. Deshalb verstehe ich nicht was so ein Interface mir bringt. Ich erzeuge doch normalerweise ein Object in dem ich den Konstruktor aufrufe und kann über dieses dann auf die öffentlichen Methoden zugreifen. Für mich sind das die Schnittstellen zu einer Klasse. Kann mir das jemand genauer erklären ?

Danke für Eure Antworten.

Gruß Magic
 
Magic1416 schrieb:
Desweiteren kann ich mit einer Klasse genau dasselbe bzw. mehr als mit einem Struct realisieren. Wozu dann noch das Struct ?
Das Struct stammt noch aus der C-Zeit, und ist quasi der Vorläufer der Classes. Structs werden in C++ und C# eigentlich nicht mehr verwendet.

Magic1416 schrieb:
Da komm ich schon zu dem nächsten Punkt. Klassen ableiten, Vererbung und Interfaces. In diesem zusammenhang gibt es dann die Möglichkeit, Methoden zu überschreiben, indem ich denselben Namen mehrmals verwende und mit den Schlüsselwörtern Virtual und override arbeite. Kann mir jemand ein Beispiel nennen wo das Sinn machen soll, den Namen einer Methode mehrfach zu verwenden ?
Stell dir vor du hast ne Klasse Bankkonto, die hat eine Methode Abheben. Jetzt erstellst du eine Klasse Sparbuch, die von der Klasse erbt. In dieser Klasse überschreibst du die Methode Abehen, so dass beim Abheben überprüft wird dass das Konto nicht in den Soll gerät.
Jetzt kannst du auf allen Objekten Geld abheben, und es wird zur Laufzeit entschieden welche Abheben-Methode genutzt wird. :)

Magic1416 schrieb:
Interfaces hab ich in dem Zusammenhang überhaupt nicht verstanden. Laut Buch sollen Sie die Handhabung wohl vereinfachen. Allerdings, wenn ich versuche ein Interface zu verwenden hab ich im Visual Studio keine Auswahl an Methoden oder sonstigen. Deshalb verstehe ich nicht was so ein Interface mir bringt. Ich erzeuge doch normalerweise ein Object in dem ich den Konstruktor aufrufe und kann über dieses dann auf die öffentlichen Methoden zugreifen. Für mich sind das die Schnittstellen zu einer Klasse. Kann mir das jemand genauer erklären ?
Eine Schnittstelle ist sozusagen eine Richtlinie die eine Klasse einhalten muss. Methoden können in einer Schnittstelle definiert werden. Alle Klassen die diese Schnittstelle implementieren, müssen eben diese Methoden mit genau diesen Signaturen aufweisen. ;)

Ich hoffe es ist dir ein wenig klarer geworden.
 
Beispiel zu einem Interface:

Stell dir vor du willst dir ein Haustier kaufen. Was für ein Tier genau das sein soll ist dir egal.
Aber es soll folgende Dinge können:
- mit Ball spielen
- In Garten von Nachbar sch*****
- Kinder mögen

Das ist gewissermaßen der kleinste gemeinsame Nenner eines Wunschhaustieres.
Jetzt kanst du ja nicht in eine Tierhandlung gehen und sagen "Ich will ein Haustiertier kaufen". Du musst schon sagen, welches konkrete Tier du willst (Hund, Katze, Hamster ...).

Um diese Sachverhalte in ein Programm abzubilden kannst du dir ein interface Haustier definieren.
Wenn du jetzt konkrete Tiere willst, musst du dir Klassen schreiben, dir das Interface Haustier implementieren.

Das heißt, dass die Klasse Hund dir drei oben genannten Methoden implementieren muss und die Klasse Katze auch.
Zusätzlich kann aber der Hund noch eine Methode holeStöckchen() haben und die Katze jageMaus().


Jetzt kannst du in deinem Programm an die Stelle wo du ein Haustier einfügen willst einfach eine Katze oder einen Hund einfügen.
Du mussst also ein konkretes Haustier-Objekt einfügen, denn von einer "Interface-Klasse" kannst du kein Objekt anlegen (so wie du kein Haustier kaufen kannst, sondern nur Hund oder Katze).

Diese "Austauschbarkeit" von Objekten, wenn die Klasse das selbe "Interface" haben nennt man Polymorphismus (für dich als weiterführendes Stichwort).
Polymorphismus ist eines der drei grundlegenden Merkmale der Objektorientierten Programmierung: Abstraktion - Vererbung - Polymorphismus.
 
Danke für Eure Antworten.
Bis auf die Sache mit den Interfaces hab ich soweit alles Verstanden, obwohl die Beispiele ja wirklich einleuchtend sind. Eine wirkliche Arbeitsersparnis sehe ich in den Interfaces allerdings noch nicht.
Ich werd die Sache mit dem Haustier einfach mal in Code umsetzen und das Ergebnis hier posten und kommentieren.
Dann seht Ihr bzw. merke ich vielleicht selbst schon, was ich nicht verstehe.

MFG
Magic
 
Die Interfaces sind auch nicht wirklich eine Arbeitserleichterung, sondern eher eine Richtlinie. (Hoffe das ist richtig so) ;)
 
So, ich habe den Code jetzt fertig:

Die Klassen:

Code:
using System;
using System.Windows.Forms;

namespace Tiere
{
	interface IBefehle
	{
		void hau_ab();
	}
	public class Haustier
	{
		protected string TierTyp;
		public Haustier()
		{
			TierTyp = "Säugetiere";
			MessageBox.Show ("Hallo Haustiere. Ihr seid "+TierTyp);
		}
		protected void komm_her(string befehl)
		{
			MessageBox.Show (befehl);
		}
		public virtual void hau_ab()
		{
			MessageBox.Show ("Haustiere !!! Haut ab");
		}
	}

	public class Hund : Haustier
	{
		public Hund() : base()
		{
			MessageBox.Show ("Hier ist der Hund");
			MessageBox.Show ("Der Hund gehört auch zu der Gruppe der " + TierTyp);
			
		}
		
		public override void hau_ab()
		{
			MessageBox.Show ("Hund !!! Hau ab");
		}
		public void fressen()
		{
			MessageBox.Show ("Der Hund frisst gerade");
		}
	}

	public class Katze : Haustier
	{
		public Katze() : base()
		{
			MessageBox.Show ("Hier ist die Katze");
		}
		
		public override void hau_ab()
		{
			MessageBox.Show ("Katze !!! Hau ab");
		}
		public void jagen()
		{
			MessageBox.Show ("Die Katze jagt gerade Mäuse");
		}
	}

	public class Hamster : Haustier
	{
		public Hamster() : base()
		{
			MessageBox.Show ("Hier ist der Hamster");
		}
		
		public override void hau_ab()
		{
			MessageBox.Show ("Hamster !!! Hau ab");
		}
		public void laufen()
		{
			MessageBox.Show ("Der Hamster läuft gerade im Laufrad");
		}
	}
}
Hier die Aufrufe der Klassen:
Code:
private void button_Haustier_Click(object sender, System.EventArgs e)
		{
			Haustier haustier = new Haustier(); //Ich dachte man kann auf die Tiere Klassen erst zugreifen, wenn
			haustier.hau_ab();					//das Objekt Haustier existiert.
		
			Hamster hamster = new Hamster(); //Die Konstruktor der Base wird nochmal aufgerufen. Steht aber auch im Buch
			hamster.hau_ab();				//die Methode der Klasse Hamster wird aufgerufen
			hamster.laufen();				// gibts nur in der Klasse Hamster

			Hund hund = new Hund();
			hund.hau_ab();
			hund.fressen();

			Katze katze = new Katze();
			katze.hau_ab();
			katze.jagen();


		}
Das Interface befindet sich Innerhalb des Namespaces. Es ist in den Methoden aufgelistet. Kann aber nichts damit machen. Das was am ehesten Funktioniert ist IBefehle bla = new IBefehle(); Die Methode hau_ab steht dann für bla zur Auswahl. Allerdings gibt das ein Kompilierfehler.
Dafür das das Interface da ist, hat es keinen ersichtlichen Nutzen oder ich hab was falsch gemacht.

Ich hab auch nicht wirklich das Gefühl, das die abgeleiteten Klassen irgendwas von der Basisklasse geerbt haben sollen. Ich habe in der Basisklasse die protected Methode komm_her. Ich hätte jetzt erwartet, das ich mit z.b. "hamster." nicht nur hau_ab und laufen angezeigt wird, sondern eben auch die Methode komm_her. Daher glaub ich dass da was nicht richtig ist mit der Vererbung. Nur die Variable TierTyp aus der Basisklasse kann ich hernehmen (siehe Klasse Hund).

Prinzipiell würd ich ein Vorteil an der Vererbung sehen, wenn ich alle gemeinsamen Methoden in der Basisklasse habe und alle speziellen eben in der entsprechenden Klasse. Das scheint in meinem Code allerdings nicht so zu funktionieren.

Ich glaub ich hab das Thema nicht wirklich verstanden.

Vielleicht kann jemand den Code korrigieren.

Gruß Magic
 
Nicht ganz richtig.
Das Folgende ist Java-Code, aber das Prinzip sollte klar werden, da Java und C# sich sehr ähnlich sind.

Mit dem Interface legst du fest, dass alle Haustiere mindestens diese zwei Methoden haben müssen. Wie diese Methoden intern dann aussehen ist den konkreten Tieren überlassen.
Du kannst in dem Interace auch keinen Code für diese beiden Methoden schreiben, weil das Aufgabe der Klassen ist, die dieses Interface implementieren.

Die konkreten Tiere implementieren dann dieses Interface.
Der Compiler zwingt dich dann dazu die zwei Methoden des Interaces bei Hund und Katze zu implementieren (also Code für diese Methoden zu schreiben.)

Und da Haustier keine Klasse ist kannst du kein Objekt davon anlegen.
PHP:
interface Haustier
{
    public void spieleInGarten();
    public void scheisseInGarten();
}

public class Hund implements Haustier
{
    // diese Methoden MÜSSEN implementiert werden
    public void spieleInGarten()
    {
        // suche Ball in Garten
    }

    public void scheisseInGarten()
    {
        // setze Häufchen in Garten
    }

    // zusätzliche Methoden nur für Hund
    public void holeStoeckchen()
    {
        // hole Stöckchen
    }
}

public class Katze implements Haustier
{
    // diese Methoden MÜSSEN implementiert werden
    public void spieleInGarten()
    {
        // klettere Baum hoch
    }

    public void scheisseInGarten()
    {
        // verbuddle Häufchen in Garten
    }

    // zusätzliche Methoden nur für Katze
    public void jageMaus()
    {
        // jageMaus
    }
}

public static void main()
{
    // du schaffst dir ein Tier an
    Haustier meinTier = new Hund();
    meinTier.spieleImGarten();
    meinTier.holeStockchen();

    // du magst den Hund nicht mehr
    meinTier = new Katze();
    meinTier.spieleImGarten();
    meinTier.jageMaus();

    Haustier nochSoEinDing = new Haustier();  // Compilerfehler, da Haustier kein konkretes Tier ist sondern ein Interface
}
 
Vielen Dank für die Antwort.

Soweit hab ich es jetzt verstanden und auch den Fehler in meinem Code gefunden. Das Interface war garnicht implementiert.

Ich hätte dann zum Schluß noch eine Frage, was das Thema Vererbung betrifft:

Es heist ja, dass abgeleitete Klassen ihre Eigenschaften von der Basisklasse erben. Was ist mit gemeinsamen Eigenschaften gemeint ? Ich verstehe darunter gemeinsame Variablen, Konstanten und Methoden, die nur von der Basisklasse selbst bzw. von den abgeleiteten Klassen ebenfalls verwendet werden können, damit ich keinen Code doppelt schreiben muß.

Ist das so korrekt, und wenn ja, warum kann ich in meinem Codebeispiel nicht auf die Methode komm_her in der Basisklasse Haustier zugreifen ?

Danke


Gruß Magic
 
Wenn du eine neue Klasse schreibst, die von einer anderen Klasse abgeleitet wird, dann werden Attribute (die Eigenschaften, also Varibalen und Konstanten) und Methoden (die Funktionen) vererbt.

Dabei kommt allerdingst die Sichtbarkeit von Attributen und Methoden zum Tragen.
Es gibt ja:
public - Sichtbar von außerhalb für alles und jeden, der darauf zugreifen will
protected - Sichtbar nur von abgeleiteten Klassen; aber nicht von außerhalb
private - Sichtbar nur innerhalb der Klasse

Beispiel:
PHP:
class Vater{
    public String name;
    protected int erbgut;
    private int kontostand;

    public void kaufeAuto();
    protected void bindeSchuhe();
    private void trinkeSchnaps();
}

class Sohn extends Vater {
    public void sinnlos() {
        name = "Alex"; // möglich, weil public von Vater geerbt :-)
        erbgut = 12; // möglich, weil protected von Vater geerbt
        kontostand = 1000000; // NICHT möglich, weil private in Vater

        kaufeAuto(); // möglich, weil public geerbt von Vater
        bindeSchuhe(); // möglich, weil protected geerbt von Vater
        trinkeSchnaps(); // NICHT möglich weil private in Vater
    }

    protected void schwachsinn()    {}
    private void bloed()    {}
}

public static void main() {
    Vater peter = new Vater();
    Sohn alex = new Sohn();

    alex.sinnlos() // möglich, weil sinnlos() public in Sohn ist
    alex.schwachsinn() // NICHT möglich, weil protected in Sohn
    alex.bloed() // NICHT möglich, weil private in Sohn

    alex.kaufeAuto(); // möglich, weil public von Vater geerbt
    alex.bindeSchuhe(); // NICHT möglich, zwar geerbt, aber nicht public
    alex.trinkeSchnaps(); // NICHT möglich, weil private
}
Deiner Methode komm_her() entspricht die Methode bindeSchuhe().
Du kannst das nicht aufrufen, weil es nicht public ist in Hund, Katze oder Hamster.
Diese haben die Methode zwar von Haustier geerbt, aber die Methode ist nach außen hin nicht sichtbar.
 
Danke,

jetzt ist mir alles klar.

Vielen Dank

Gruß
Magic
 
AW: Re: [C#] Allgemeine Programmier Fragen

hmm noch eine kleine Frage für was hat man "protected", wenn man sie nicht verwenden kann. (Anfängerfrage ich weiss :>)

Gruß Denis
 
AW: Re: [C#] Allgemeine Programmier Fragen

den[N]is schrieb:
hmm noch eine kleine Frage für was hat man "protected", wenn man sie nicht verwenden kann. (Anfängerfrage ich weiss :>)

Gruß Denis

Wie schon Boron sagte
protected - Sichtbar nur von abgeleiteten Klassen; aber nicht von außerhalb
Also kann man protected Methoden sehr wohl verwenden durch Aufrufen in der abgeleiteten Klasse.

Gruß

Thunder Cat
 
AW: Re: [C#] Allgemeine Programmier Fragen

Ach ok, aber eben nicht von außen heraus. Ok habs verstanden hatte ein Brett vor dem Kopf :D
 
AW: Re: [C#] Allgemeine Programmier Fragen

Boron schrieb:
PHP:
class Vater{
....

class Sohn extends Vater {
...

Hier muss ich aber gleich mal meckern - auch wenn es erstmal nur um's Beispiel geht :)

Und zwar bedeutet (öffentliche) Vererbung "ist ein" und nicht "hat ein" - was in diesem Falle richtig wäre. Und zwar heißt "ist ein" "verhält sich wie ein" im softwaretechnischen Sinne. Erstmal ist ein Sohn kein Vater, auch wenn er einer werden kann. Deshalb ist es z.B. auch falsch ein Quadrat von Rechteck abzuleiten, denn ein Quadrat verhält sich nicht wie ein Rechteck. Dazu gibt es eine hübsche "Geschichte". Kann ich mal raussuchen wenn Interesse besteht.
 
Na dann lass dich nicht lumpen und such mal die Anekdote raus :).
Code:
[SIZE="4"]class Hungriger {
  void essen( void ) = 0;
};

class Boron : public Hungriger {
   void essen( void ) {
      // Schaufelt sich ein Wurstbrot rein
   }
};[/SIZE]
Merke: Boron "verhält sich wie ein" Hungriger :D.
 
Boron schrieb:
Merke: Boron "verhält sich wie ein" Hungriger :D.
LOL :) In diesem Falle würde ich dir aber ein Singleton nahelegen... :D



Also hier ist das Ding. Viel Spaß beim Lesen. ;) Und mit freundlichem Gruß an Volkard Henkel.
Herr Bebel war dareinst ein ganz normaler Schüler. In seiner Jugend zeigten sich erste Auffälligkeiten, was seinen Umgang mit elektischen Geräten betraf. Diese verschlimmerten sich und er wurde Informatiker. Seiner Zeit malte man noch Struktogramme, statt wirklich zu programmieren, denn elektischer Strom war zu teuer für Hochschulen. Mit echtem Strom arbeiten durften nur hochspezialisierte Programmierer.
Er brachte es zu ganz ansehnlichem Ansehen in seinem Beruf, fand eine verständnisvolle Frau und kam ein gutes Jahrzehnt später hatte er auch Auto, Haus, Yacht und Kinder.
Doch das Schicksal nahm seinen Lauf und böse Leute erfanden etwas furchtbares namens "Objektorientierung". Die Objektorientierung störte die Gedankengänge aller braven Informatiker und verwirrte sie dermaßen, daß man dareinst sogar daran glaubte, die Roten hätten "Objektorientierung" in geheimen unterirdischen Labors entwickelt, um die westliche Welt zu zerstören. Es war nicht nachzuweisen, doch das Buch der Pandorra war nunmal geöffnet.
Nach zahllosen intellektuellen Bürgerkriegen einigte man sich letztlich auf einen modus vivendi, man strebte kompromisslos Kompromisse an und brachte die Welt wieder ins Lot, indem man "Objektorientierung" zum Gott erhob, damit sie einem nichts böses mehr antut.
In der neuen Weltordnung malte man UML-Diagramme, statt wirklich zu programmieren, denn elektrischer Strom war zu teuer für Hochschulen. Mit echtem Strom arbeiten durften nur hochspezialisierte Fachinformatiker.
Herr Bebel stieg gezwungenermaßen auch um, denn jeder Informatiker mußte dem neuen Gott dienen. Aber er achtete die Gebote nicht. Insbesondere beachtete er nicht das Gebot
"Du sollst dafür sorgen, daß öffentliche Erblichkeit "ist ein" bedeutet".
Er arbeitete inzwischen als Star-Programmierer in der Automobilindustrie. Ganz nach den neuen Geboten implemetierte er auch einen neuen Motor. Und später ein ganzes Auto.
PHP:
class Auto:public Motor{...};
Das war auch beinahe perfekt. Doch leider nur beinahe. Die drei einzigen Methoden von Motor waren gasgeben(), anmachen() und ausmachen(). Da ein auto das auch kann, war es für den armen Herrn Bebel ganz logisch, daß ein Auto ein Motor ist. Ein Motor mit Blech drumherum.
Doch das Schicksal nahm seinen Lauf.
Der schicksalsgeplagte Herr Bebel mußte in der Tat alle drei Methoden von Motor in Auto redefonieren, weil durch das ganze Blech drumherum die Qualität des Amachens, des Gasgebens und des Ausmachens verändert wurde. Es war einach etwas anderes, das ganze Auto anzumachen, als nur den Motor. Frühe Versuche, daß der Motor sein ihn besitzendes Auto kennt, waren ganz gescheitert, aber zum Glück ohne erhebliche Kosten.
Es begab sich, daß ein jedes mal, daß Motor eine neue Methode bekam, sie doch früher oder später dem Auto verboten werden mußte, oder im Auto redefiniert werden mußte. Inzwischen wissen wir, daß das einfach daran lag, daß ein Auto kein Motor IST, sondern daß ein Auto einen Motor HAT. Herr Bebel vergaß oft, die Methoden zu redefinieren, und fatal wurde es, als 100000 Luxusautos ausgeliefert wurden, die "zünden" konnten.
Alsbald arbeitslos kümmerte er sich um die Kinder. Seine Frau verließ ihn mitsamt den Kindern, als er die Kinder schnitt und nicht deren Fußnägel (Kinder HABEN Furßnägel, aber SIND keine.).
Vor Gericht beteuerte er, daß er eine Schere (Er HATTE eine Schere, aber er WAR keine.) gewesen sei und wurde in eine Psychiatrische eingeliefert.
Nachdem er dort seine Hand (Seine Hand HATTE ein Brötchen aber es WAR keines.) mit Marmelade bestrich und hineinbiß, nachdem er wegen eines Pickels am Hals sich zu erwürgen versuchte (Sein Hals HATTE....) und ähnlicher nur mit knapper Not abwendbarer Selbstmordversuche, wurde er medikamentös dauerruhiggestellt.
 
Zurück
Oben