Entwickler-Ecke

Basistechnologien - Probleme mit Variablen und Vererbung


nerdfactor - Do 14.10.10 13:21
Titel: Probleme mit Variablen und Vererbung
Hallo,
ich habe zur zeit ein problem bei einem kleinen projekt mit vererbung und dem zugriff auf variablen innerhalb der objekte. hier mal ein kurzes beispiel:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
static void Main(String[] args) {
  ChildClass cc = new ChildClass();
}

class BaseClass {

  public String str = "BaseClass";

  public BaseClass() {
    this.doSomething();
  }

  public void doSomething() {
    Console.WriteLine(this.str);
  }
}

class ChildClass : BaseClass{

  new public String str = "ChildClass";

  public ChildClass() : base(){
      
  }

  public void doSomethingElse() {
    //does something else that has nothing todo with doSomething
  }
}


wenn ich das ausführe, wird in der konsole "BaseClass" ausgegeben. ich hätte allerdings erwartet, das "ChildClass" ausgegeben wird, da doSomething von ChildClass aufgerufen wird und str dort den wert "ChildClass" hat.

habe ich da einfach nur ein denkfehler, oder etwas in der richtung? und wie kann ich das erreichen, was ich eigentlich erwartet habe?

ich hoffe jemand kann mir helfen.


Th69 - Do 14.10.10 13:33

Kennst du schon das Schlüsselwort 'virtual'?

Du hast in ChildClass die Variable mittels 'new' überschrieben (das man nur in sehr wenigen Situationen einsetzen sollte), jedoch kennt BaseClass nur die eigene Variable 'str' und gibt daher dessen Inhalt "BaseClass" aus.

Richtig wäre es also so:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
static void Main(String[] args) {
  ChildClass cc = new ChildClass();
}

class BaseClass
{
  public virtual String str = "BaseClass";

  public BaseClass() {
    this.doSomething();
  }

  public void doSomething() {
    Console.WriteLine(this.str);
  }
}

class ChildClass : BaseClass
{
  public override String str = "ChildClass";

  public ChildClass() : base(){
      
  }
}

Beachte also die beiden Schlüsselwörter 'virtual' und 'override' (zum Überschreiben).

Ich nehme mal an, daß du noch Anfänger bist und daher dies eines deiner ersten Übungsprogramme ist? Besser ist es nämlich, wenn du Eigenschaften (Properties) bzw. die Methoden als 'virtual' deklarierst. Klassenmember (Felder) sollten außerdem immer 'private' sein.


DuxGladii - Do 14.10.10 13:36

Hallo nerdfactor,

da du doSomething nicht überschreibst, wird die Funktion der Basis-Klasse aufgerufen, die den String der Basis-Klasse zurückgibt. Willst du den String der ChildClass zurückgeben, kannst du die Funktion in der ChildClass überschreiben mit


C#-Quelltext
1:
2:
3:
4:
public override void doSomething()
{
return this.str; // wenn du hier base.str schreibst, solltest du BaseClass zurückgeliefert bekommen
}


nerdfactor - Do 14.10.10 13:46

ja c# ist neu für mich. ich steige um von webentwicklung mit php, ruby und javascript. anscheinend habe ich daher tatsächlich denkfehler wenn es um das static binding geht.

wenn ich die variablen um virtual bzw. override ergänze, lässt sich das programm nicht kompilieren mit dem hinweis "The modifier 'virtual' is not valid for this item" bzw. "The modifier 'override' is not valid for this item".
doSomething in ChildClass zu überschreiben würde doch den ganzen sinn aus der verwerbung nehmen. immerhin möchte ich ja das ChildClass die funktionalität von BaseClass erbt damit ich sie nicht mehrfach schreiben muss.

es bleibt daher noch die frage wie ich das erreiche was ich eigentlich haben möchte.


DuxGladii - Do 14.10.10 13:53

ChildClass erbt ja auch die Funktionalität von BaseClass, aber du willst ja die Funktion verändern, weil du nicht die Variable von BaseClass sondern von ChildClass zurückgeben willst, deshalb musst du sie überschreiben (virtual hab ich in meinem vorigen Post vergessen zu erwähnen).


Th69 - Do 14.10.10 14:15

Sorry, 'virtual' funktioniert ja gar nicht bei Klassenmembern (daher auch mein Hinweis bzgl. Eigenschaften und Methoden -).

Du könntest also dann folgendes verwenden (in Anlehnung an den Code von DuxGladii):

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
static void Main(String[] args) {
  ChildClass cc = new ChildClass();
}

class BaseClass
{
  private String str = "BaseClass";

  public BaseClass() {
    this.doSomething();
  }

  public virtual void doSomething() {
    Console.WriteLine(this.str);
  }
}

class ChildClass : BaseClass
{
  private new String str = "ChildClass";

  public ChildClass() : base(){
      
  }

  public override void doSomething() {
    Console.WriteLine(this.str);
  }
}

Jede Klasse hat nun also eine private Variable (hier dann doch mittels 'new' überschrieben) und implementiert dann jeweils 'doSomething'.

Besser aber nun die Variante mit Eigenschaften:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
static void Main(String[] args) {
  ChildClass cc = new ChildClass();
}

class BaseClass
{
  public virtual String Str { get { return "BaseClass"; } }

  public BaseClass() {
    this.doSomething();
  }

  public void doSomething() {
    Console.WriteLine(this.Str);
  }
}

class ChildClass : BaseClass
{
  public override String Str { get { return "ChildClass"; } }

  public ChildClass() : base(){
      
  }
}


nerdfactor - Do 14.10.10 14:20

ok das scheint zu funktionieren. vielen dank.
da werde ich mir wohl das mit dem Properties genauer angucken müssen.


Ralf Jansen - Do 14.10.10 14:32

Da das mit virtual/override geklärt ist nur folgendes kurz zu deinem geschilderten Anwendungsfall. Wenn das nicht nur ein Beispiel ist sondern dein wirklicher Anwendungsfall dann kommst du an den Klassennamen einfach über das Type Objekt deiner Klasse.

Also anstatt eine Literal zurück zu liefern einfach in BaseClass folgendes machen.

C#-Quelltext
1:
  public String Str { get { return this.GetType().Name; } }                    

Wenn du denn Namen nur veröffentlichst um darüber zu prüfen was du für einen Typ den gerade an der Hand hast so solltest du auch eher den is [http://msdn.microsoft.com/de-de/library/scekt9xw.aspx] Operator verwenden.