Jump to content
Unity Insider Forum

C# Grundlagen - Vererbung in Unity3D


Carsten

Recommended Posts

Im Rahmen meiner KI-Reihe hab ich in einem Tutorial mal das Thema Vererbung in C# etwas unter die Lupe genommen:

 

Was ist Vererbung? Wofür brauch ich das? Und vorallem: Wie mach ich das?

Diesen Fragen will in meinem 13 minütigen Video auf den Grund gehen.

 

Zum Tutorial: Unity3D Tutorial - C# Vererbung

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo Sascha,

 

ich weiß jetzt gerade nicht wirklich was Du mit "Werte erbender Typen" meinst.

 

Werte vererbt man ja nicht sondern nur die Eigenschaften und Methoden (und deren Variablen etc.) einer Klasse. Und das Nutzen einer Klasse bzw. eines Skripts als Basisklasse für eine andere funktioniert wunderbar, wie du dem Video entnehmen kannst.

 

Aber vielleicht missverstehe ich dich auch gerade ein bisschen ... :blink:

 

Gruß Carsten

Link zu diesem Kommentar
Auf anderen Seiten teilen

Da hast Du natürlich recht, sowas geht nicht. Aber das geht auch grundsätzlich nicht, denn sonst könnte man ja auf ein Variable jedes Skript ziehen, weil ja alle Unity-Skripte von MonoBehaviour erben.

 

So ein Verhalten sollte man über Schnittstellen lösen können, wobei ich das in Unity noch nicht gemacht habe.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 8 years later...

Auch wenn das Thema schon älter ist, hätte ich auch mal eine Frage.

In einem Tutorial(1.Bild) wurde die Vererbung vorgestellt.

Nun wollte ich das mal ausprobieren(2.Bild) und habe ein funktionierendes Script um die Klasse "Superhelden" erweitert(rot eingerahmtes). Doch funktioniert das nicht und Unity gibt die Meldungen aus:

Assets/03_C#_Grundlagen/Scripts/S31ConstructorUndVererbung.cs(29,14): error CS0101: The namespace `global::' already contains a definition for `Mensch'

&

Assets/03_C#_Grundlagen/Scripts/S31ConstructorUndVererbung.cs(53,14): error CS0101: The namespace `global::' already contains a definition for `SuperMensch' .

Funktioniert das nur von einem Script zum anderen oder geht das auch innerhalb eines Scripts? Falls ja, was habe ich falsch gemacht?

vererbung2.jpg

vererbung.jpg

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ahja, hatte sie wirklich umbenannt und nicht gesehen das die alte noch/wieder da war.

Nun habe ich aber diese Fehlermeldungen:

Assets/03_C#_Grundlagen/Scripts/S31ConstructorUndVererbung.cs(20,29): error CS1729: The type `SuperMensch' does not contain a constructor that takes `3' arguments

Assets/03_C#_Grundlagen/Scripts/S31ConstructorUndVererbung.cs(57,12): error CS1729: The type `Mensch' does not contain a constructor that takes `0' arguments

Wenn ich das richtig verstehe, wird die Klasse nicht ausgelesen.  Man kann doch schon vorhandenes erweitern und muß nicht jedesmal alles neu schreiben, oder?

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Auf dem Screenshot von deinem Code, hat die Klasse Mensch einen Konstruktor, der drei Argumente erwartet.

Durch die Vererbung musst du den Konstruktor der Basisklasse bedienen. Dieser erwartet zwingend drei Argumente. Entweder du erstellst in der Basisklasse zusätzlich einen Konstruktor, der 0 Argumente akzeptiert oder du übergibst die Argumente mit dem Schlüsselwort "base" an die Basisklasse.

Vereinfacht dargestellt entweder:

    public class Mensch
    {
        public Mensch(int dasAlter, string derName, string derBeruf)
        {

        }

        public Mensch()
        {

        }
    }

    public class SuperMensch : Mensch
    {
        public SuperMensch(int dasAlter, string derName, string dieFaehigkeit)
        {

        }
    }

 

oder:

    public class Mensch
    {
        public Mensch(int dasAlter, string derName, string derBeruf)
        {

        }
    }

    public class SuperMensch : Mensch
    {
        public SuperMensch(int dasAlter, string derName, string dieFaehigkeit, string derBeruf) : base (dasAlter, derName, derBeruf)
        {

        }
    }

 

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Also muß ich doch nochmal alles angeben.

Im Video(1.Bild) sagt er: "die klasse Wassermonster kann alles was die Monster können, aber zusätzlich noch schwimmen..."

Deshalb bin ich davon ausgegangen  das man nicht wieder alles angeben muß.

 

So wie in deinem 1. bsp hatte ich es schon, bis auf die 2.

public Mensch()

Wozu wäre die denn gut?

 

zum 2, bsp.

Gibt man in dem Konstruktor nicht nur das an, was auch vergeben ist( der Beruf soll ja nicht angezeigt werden)?

bei mir

SuperMensch held1 = new SuperMensch(100, "Superman", "fliegen");
.
.
public SuperMensch (int dasAlter, string derName, string dieFaehigkeit)

wenn ich dann das mit Base probiere, bekomme ich auch Fehlermeldungen:

public SuperMensch (int dasAlter, string derName, string dieFaehigkeit) :base(dasAlter, derName, derBeruf)

Assets/03_C#_Grundlagen/Scripts/S31ConstructorUndVererbung.cs(57,102): error CS0103: The name `derBeruf' does not exist in the current context

wenn ich dann "derBeruf" rausnehme, kommt dies:

Assets/03_C#_Grundlagen/Scripts/S31ConstructorUndVererbung.cs(57,78): error CS1729: The type `Mensch' does not contain a constructor that takes `2' arguments

 

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Mit der Zeile:

 

public SuperMensch (int dasAlter, string derName, string dieFaehigkeit) :base(dasAlter, derName, derBeruf)

 

übergibst du dasAlter, derName, derBeruf an den Konstruktor der Basisklasse (durch die Verwendung von :base(dasAlter,derName,derBeruf) der in diesem Fall 3 Argumente erwartet. "derBeruf" ist aber unbekannt, da an den Konstruktor von SuperMensch die Variablen "dasAlter, derName, dieFaehigkeit" übergeben werden.

Das sagt die folgende Fehlermeldung aus:

Zitat

Assets/03_C#_Grundlagen/Scripts/S31ConstructorUndVererbung.cs(57,102): error CS0103: The name `derBeruf' does not exist in the current context

Wenn du dann wie von dir Beschrieben "derBeruf" wieder raus nimmst, werden wieder nur zwei Argumente an den Konstruktor der Basisklasse übergeben. Dadurch erhälst du die folgende Fehlermeldung:

Zitat

Assets/03_C#_Grundlagen/Scripts/S31ConstructorUndVererbung.cs(57,78): error CS1729: The type `Mensch' does not contain a constructor that takes `2' arguments

 

In dem Screenshot aus deinem Tutorial sind gar keine Konstruktoren angegeben wodurch das "Problem" nicht entsteht.

Der Konstruktor wird immer aufgerufen, wenn ein neues Objekt vom Typ dieser Klasse erstellt wird über z.B. SuperMensch test = new SuperMensch()

Es besteht die Möglichkeit für jede Klasse mehrere Konstruktoren anzugeben. Dann wird je nachdem welche Parameter übergeben werden der richtige "ausgewählt".

Wenn du nun über

public Mensch()
{

}

einen weiteren Konstruktor der Klasse Mensch hinzufügst, kann ein Objekt vom Typ Mensch entweder über

Mensch test1 = new Mensch() // ohne Argumente

oder mit

Mensch test2 = new Mensch(100, "Superman", "fliegen") // mit Argumente

erstellt werden. Da in diesem Fall, die Klasse Mensch keine Argumente zwingend erwartet (es wird ja entweder der Konstruktor ohne Argumente aufgerufen oder eben mit drei Argumenten) kann deine Klasse SuperMensch von Mensch erben ohne Argumente zu übergeben.

 

Das ganze ist auch ganz gut unter: https://docs.microsoft.com/de-de/dotnet/csharp/programming-guide/classes-and-structs/using-constructors beschrieben.

Ich hoffe ich konnte es einigermaßen verständlich beschreiben.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich glaub langsam kapier ichs. Ich müßte also für jede neue Unterklasse auch einen neuen Konstruktor anlegen, wenn ich andere Werte übernehmen will.

Macht das ganze ja nicht wirklich einfacher.

 

Nun habe ich einen mit "public Mensch(int dasAlter, string derName){}" angelegt(ohne die Argumente ging es auch nicht), allerdings fehlen die Werte von der Klasse Mensch in der Ausgabe: die Fähigkeit von  ist fliegen und dessen Alter beträgt: 0

Es geht nur wenn ich wirklich alles reinschreibe  public Mensch(int dasAlter, string derName)    {  alter = dasAlter; name = derName;    }

Da sehe ich dann aber nicht, was mir die Vererbung bringen soll. Da kann ich ja gleich in der Klasse alles neu schreiben.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wenn Du in einer erbenden Klasse Parameter im Konstruktor übergibst, musst Du diese an die Basisklasse weiterreichen.

public class Mensch
{
  	protected readonly int alter;
  
	public Mensch(int alter)
	{
		this.alter = alter;
	}
}

public class SuperMensch : Mensch
{
	public SuperMensch(int alter) : base(alter)
	{
	}
}

Statt im Konstruktor kannst Du auch Eigenschaften beim Erzeugen vom Objekt setzen. Dies hat Vor- und Nachteile.

public class Mensch
{
  	private int alter;
  	private string name;
  
  	public int Alter
    {
      get 
      {
        return alter;
      }
      
      set
      {
        alter = value;
      }
    }
  
  	public int Name
    {
      get 
      {
        return name;
      }
      
      set
      {
        name = value;
      }
    }
}

public class SuperMensch : Mensch
{
}

//... irgendwo
var superMensch = new SuperMensch()
{
  Alter = 10,
  Name = "Hans Wurst"
};

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Zitat

Da sehe ich dann aber nicht, was mir die Vererbung bringen soll. Da kann ich ja gleich in der Klasse alles neu schreiben.

Die Vererbung bietet dir ja die Möglichkeit auch Methoden der Klasse von der du erbst zu nutzen.

z.B. könntest du in deiner Klasse "Mensch" Variablen für Lebenspunkte, Erfahrungspunkte usw. haben. Deine Klasse Supermensch hat dann z.B. Variablen und Methoden für Superkräfte die gewisse Dinge tun.

Deine Klasse Mensch hat aber z.B. bereits Methoden um Lebenspunkte hinzuzufügen, abzuziehen usw. Diese müsstest du dann in der Klasse Supermensch nicht noch einmal schreiben sondern könntest die Methode aus der Basisklasse verwenden.

Solltest du dann doch einmal eine Methode aus der Basisklasse "Mensch" ändern wollen in "Supermensch" kannst du diese "überschreiben" oder "erweitern".

Override - https://docs.microsoft.com/de-de/dotnet/csharp/language-reference/keywords/override

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 22 Stunden schrieb amdbuster:

Da sehe ich dann aber nicht, was mir die Vererbung bringen soll. Da kann ich ja gleich in der Klasse alles neu schreiben.

Es gibt genau zwei Gründe für Vererbung: Polymorphismus, wie bereits erwähnt, und Verhinderung von Code-Duplizierung.

"Guter Code" definiert sich nicht dadurch, dass er funktioniert, sondern durch Meta-Qualitäten. Das wären so Sachen wie Lesbarkeit, Wartbarkeit, Modularität, Robustheit. Code-Duplizierung, also "alles neu schreiben", bedeutet schlechte Robustheit. Denn wenn du dann feststellst, dass dein "Mensch" doch etwas anders funktionieren soll, darfst du erstmal an beiden Stellen, an denen du definiert hast, wie ein Mensch funktioniert, deinen Code abändern. Wenn du dann noch mehr "Mensch"-Klassen hast, dann steigt dein Änderungsbedarf proportional. Wenn du dann vergisst, eine der Änderungen zu machen, hast du direkt Fehlerpotential des Todes.

Trotz alledem muss ich sagen: Ich baue selber ungefähr niemals Vererbungshierachien, wenn es um Komponenten in Unity geht. Denn Tatsache ist, dass alles, was du mit Vererbungshierarchien bauen kannst, auch mit Komponenten gebaut werden kann. Komponentenklassen, die voneinander erben, sind nie nötig und daher selten sinnvoll. Und Vorteile gibt's auch noch dazu. Von daher würde ich auf jeden Fall empfehlen zu lernen, wie Vererbung funktioniert und was man damit macht, aber in Unity für Komponenten verwenden... eher nicht.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Lädt...
×
×
  • Neu erstellen...