# mehrere klassen extenden



## noisebreath (20. Jan 2009)

hi

wie isn die syntax wenn ich mehrere dinge extenden will?

bla extends bla1 und bla 2

greez


----------



## Loki (20. Jan 2009)

Wenn du mit "extenden" erweitern meinst, dann seih hier gesagt, in Java gibts nur Einfachvererbung. Wenn du mehr willst, dann bitte über Interface.


----------



## Der Müde Joe (20. Jan 2009)

nein.

Java kennt keine multiple inheritance.

aber man kann mehrere implements

extends abc implements a,b,c,d


----------



## Ebenius (20. Jan 2009)

Geht nicht. In Java gibt's keine Mehrfachvererbung. Jede Klasse (außer Object) erbt von genau einer Klasse direkt, kann aber beliebig viele Schnitstellen implementieren. 
	
	
	
	





```
class MyPanel extends javax.swing.JPanel implements java.io.Serializable, java.awt.ActionListener {
  // ...
}
```

Ebenius


----------



## noisebreath (20. Jan 2009)

lame....


----------



## SvenK (20. Jan 2009)

noisebreath hat gesagt.:
			
		

> lame....


Nicht wenn man verstanden hat, wieso das so gehandhabt wird. 


Schau dir mal ein C++-Programm mit Mehrfachvererbung an, da weisst du nich mehr wo hinten und vorne ist. Mehrfachvererbung kann seine Vorzüge haben, aber die wenigsten setzen sie diskret ein, sondern wenn schon, denn schon .... und am Ende weisst du nicht mehr, von wo welche Methode ererbt wurde

Außerdem sind Interfaces das beste, was der Menschheit seit Erfindung des automatischen Rückenkratzers passiert ist ....


----------



## ARadauer (20. Jan 2009)

Vererbung wird überschätzt! Komposition und Aggregation ist oft besser. 

Warum sollte mein Datencontainer eine Liste sein, wenn er eine Liste enthalten kann und das Interface einer Liste nach aussen implementieren kann. 10 Stufige Verbungshirachien wo in jeder Stufe mal eine Methode überschrieben wurde sind nicht garde lustig zu debuggen....


----------



## Murray (20. Jan 2009)

noisebreath hat gesagt.:
			
		

> wie isn die syntax wenn ich mehrere dinge extenden will?
> 
> bla extends bla1 und bla 2



Nur der Vollständigkeit halber: Interfaces können durchaus mehrere andere Interfaces beerben; die Syntax ist dann

```
public interface Bla extends Bla1, Bla2 {
}
```


----------



## Marco13 (20. Jan 2009)

Wie wär's: Ich schreib' dir ein (nicht-obfuskiertes) C++-Programm mit 20 Zeilen, bestehend aus 2-3 Klassen, wo effektiv nur "eine" Methode aufgerufen wird, und du wirst mir aus dem stegreif NICHT sagen können, welche Methode das ist, die da aufegrufen wird. Mit Java ist das schon schwieriger.


----------



## Leroy42 (21. Jan 2009)

Wow!

Würde mich mal interessieren.


----------



## Ariol (21. Jan 2009)

Leroy42 hat gesagt.:
			
		

> Wow!
> 
> Würde mich mal interessieren.



Mich auch^^


----------



## Zed (21. Jan 2009)

Du hast es uns angeboten. Will auch mitraten!!!


----------



## Ebenius (21. Jan 2009)

Zed hat gesagt.:
			
		

> Du hast es uns angeboten. Will auch mitraten!!!


Bin auch dabei.


----------



## Murray (21. Jan 2009)

Hier sind wohl unerwartet viele "CPlusPlusser" unterwegs?


----------



## Marco13 (21. Jan 2009)

Huii, dass da so viele so draufhüpfen... Na gut, trotz der Problematik, dass man oft schon an der Fragestellung die Antwort ablesen kann, hier das kleine Quiz:

```
#include <iostream>
using namespace std;

class A
{
      public : virtual void f() {  cout << "A" << endl;  };
};

class B : virtual public A 
{
      public : virtual void f() { cout << "B" << endl;  };
};

class C : virtual public A {};

class BC : public B, public C {};

int main()
{
    BC bc;
    C* c = & bc;
    c->f();
    system("PAUSE");
    return 0;
}
```
Ist die Ausgabe A, B oder läßt es sich aufgrund von Mehrdeutigkeit nicht compilieren?


EDIT: Da stand ursprünglich was fehlerhaftes, durch das & .... Jetzt müßt's stimmen...


----------



## Landei (21. Jan 2009)

Es sei darauf hingewiesen, dass man in Java über Reflection (genauer gesagt über dynamic proxy) auch so eine Art Mehrfachvererbung realisieren kann, aber das ist etwas für sehr, sehr kranke Geister.

Mehrfachvererbung gibt es übrigens auch in einer "sauberen" Variante, der sogenannten Mixin-Vererbung (ich brauche sicher nicht zu betonen, welche auf der JVM laufende Sprache sowas hat)


----------



## Zed (21. Jan 2009)

Mein Tip ist:
Du speicherst in c die Adresse von der Klasse BC. Der Pointer c ist aber von Typ C welcher die Klasse C representiert und C erbt nur von A so wird denke ich die Funktion f() von A aufgerufen. Aber zu 100% sicher bin ich mir da nicht.


----------



## Ebenius (21. Jan 2009)

Zed's Begründung glaub ich nicht. Die Vererbung ist rein virtuell. Ich gehe davon aus, dass es wegen Mehrdeutigkeit nicht kompiliert.


----------



## Ariol (21. Jan 2009)

Ich denke das B.f() aufgerufen wird.

Das erstellte Objekt bc ist vom Typ BC, welches zuerst B erbt:
bc.f() ruft also B.f() auf.

Durch das Erstellen eine C-Pointers aus bc wird ja nur die Adresse übergeben. Da sowohl A als auch B und C die Funktion f() besitzen ist der Aufruf von c->f() kein Problem -> Da aber in Wirklichkeit ein BC-Objekt dahinter steckt wird BC.f() aufgerufen, was wiederum B.f() aufruft.

Ist das so richtig?


----------



## Landei (21. Jan 2009)

Pseudomehrfachvererbung in Java (für sehr, sehr kranke Gemüter)

Erst Mal ein paar Interfaces und Klassen:

```
public interface Cat {
   public void purr();
}

public interface Dog {
   public void bark();
}

public class Angora implements Cat {
    public void purr() {
        System.out.println("purrrrrr");
    }
}

public class Beagle implements Dog {
    public void bark() {
        System.out.println("wuff");
    }
}
```

Und jetzt die Gentechnik:

```
public class BioLab {

   public static Object breed(final Object... args) {
       Set<Class> interfaces = new HashSet<Class>();
       for(Object o : args) {
           for(Class<?> interf : o.getClass().getInterfaces()) {
               interfaces.add(interf);
           }
       }
       return Proxy.newProxyInstance(BioLab.class.getClassLoader(), interfaces.toArray(new Class[0]),
        new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
                if (arguments == null) {
                    arguments = new Object[0];
                }
                for(Object o : args) {
                    for(Method m: o.getClass().getMethods()) {
                        if (m.getName().equals(method.getName())) {
                            Class[] classes = m.getParameterTypes();
                            if (classes.length == arguments.length) {
                                boolean match = true;
                                for(int i = 0; i < arguments.length; i++) {
                                    if (! classes[i].isAssignableFrom(arguments[i].getClass())) {
                                        match = false;
                                        break;
                                    }
                                }
                                if (match) {
                                   return m.invoke(o, arguments);
                                }
                            }
                        }
                    }
                }
                return null;
            }
       });
   }

   //for testing
   public static void main(String... args) {
       Object chimaira = breed(new Beagle(), new Angora());
       System.out.println(chimaira instanceof Dog);
       System.out.println(chimaira instanceof Cat);
       ((Dog)chimaira).bark();   
       ((Cat)chimaira).purr();
   }

}
```

WARNUNG: Solche Konstruktionen sind gemeingefährlich (z.B. ruft der Code einfach die erste "passende" Methode auf) und sollten nicht in freier Wildbahn verwendet werden.


----------



## Zed (21. Jan 2009)

Ich hab mal das kleine C++ Programm laufen lassen und es wird immer B aufgerufen. Hätte ich nicht gedacht


----------



## Marco13 (22. Jan 2009)

Jupp, es wird B ausgegeben. Eine _genaue_ Begründung traue ich mir nicht zu (nur ein paar Arumentationsbrocken). Das überlasse ich den C++-Experten.

Ein Aspekt, den ich daran kritisch finde, ist, dass das engültige Verhalten vom Vorhandensein oder nicht-Vorhandensein des Schlüsselworts "virtual" an der einen oder anderen Stelle abhängt (auch innerhalb schon "Schwesterklassen"). Es ist einfach unübersichtlich und schwer nachvollziehbar.


----------



## maki (22. Jan 2009)

> Jupp, es wird B ausgegeben. Eine genaue Begründung traue ich mir nicht zu (nur ein paar Arumentationsbrocken). Das überlasse ich den C++-Experten.


Bin kein C++ Experte, meine aber mich erinnern zu können das der Kompiler festlegt, wie die Aufrufe aufgelöst werden können, und zwar anhand der Reihenfolge der vererbenden Klassen.

Möchte mal jemand testen was passiert wenn anstatt 

```
class BC : public B, public C {};
```
die Reihenfolge umgedreht wird:

```
class BC : public C, public B {};
```

Jedenfalls sind solche "Regeln" die nirgendwo klar definiert sind nicht gerade ein Garant für guten Quellcode der verständlich ist.


----------



## Zed (22. Jan 2009)

Mann muss aber schon zugeben das man das Problem umgehen kann durch eine konkrete Bezeichung bei Methoden.
Wer eine Mehrfachvererbung nutzt und Methoden gleich benennt ist selber schuld wenn er erst debuggen muss um den Fehler zu finden.


----------



## didjitalist (23. Jan 2009)

genau das ist einer der gründe, warum java keine mehrfachvererbung bietet. alles ist wunderbar, solange man sich nur in seinem eigenen code bewegt. aber lass mal mehrere leute am selbe code rumfuhrwerken. wenn die nicht höllisch aufpassen, gibs irgendwann ne klassenhierarchie, da kannst dir hände und füsse dran wärmen.


----------



## maki (23. Jan 2009)

Zed hat gesagt.:
			
		

> Mann muss aber schon zugeben das man das Problem umgehen kann durch eine konkrete Bezeichung bei Methoden.
> Wer eine Mehrfachvererbung nutzt und Methoden gleich benennt ist selber schuld wenn er erst debuggen muss um den Fehler zu finden.


Bedenkst du dabei auch dass es Methoden gibt die jedes Objekt immer anbietet wie equals, hashcode, toString etc. pp.?  :wink: 

Kurzum: Die Mehrfachvererbung in C++ ist nicht gerade durchdacht (wie viele andere Dinge in C++ auch), nicht umsonst hat schon M$ in VC++ die Mehrfachableitung von CObject verboten.


----------



## _fliX (7. Jul 2009)

Hallo,

ich habe gerade mal einen Test gemacht, bezüglich Vererbung. Es wird ja gesagt, dass es keine richtige Mehrfachvererbung gibt. Was ist das denn wenn ich folgendes Beispiel habe:

Es gibt die klassen A,B,C
B erbt von A und C erbt von B

Trotzdem kann ich doch in der Klasse C Dinge der Klasse A aufrufen. Genauso wird auch der Konstruktor von A und B ausgeführt, wenn ich ein Objekt der Klasse C instanziiere.

Ist das keine Mehrfachverberung? Was genau soll dann Einfachverberung bedeuten?


----------



## faetzminator (7. Jul 2009)

maki hat gesagt.:


> Möchte mal jemand testen was passiert wenn anstatt
> 
> ```
> class BC : public B, public C {};
> ...



und was wär wenn das funktionieren würde? Wie könnte ich dann aus BC explizit B aufrufen wollen würde? super<B>.doSomething() oder was  ?


----------



## Paddelpirat (7. Jul 2009)

@_flix
In dem Fall:
Es gibt die klassen A,B,C
B erbt von A und C erbt von B

kannst du z.B. annehmen du hast eine Methode doSomething() in der Klasse A
Nun sagst du das B von A erbt. Dann hast du die zwei Möglichkeiten, dass B die Methode doSomething() überschreibt, oder sie so lässt wie sie in A definiert wurde.

In der klasse C, die von B erbt, ist es nun so dass die Methode doSomething() halt die ursprüngliche Form hat (wenn du sie nicht in B überschireben hast), oder sie so aussieht wie du sie in B überschrieben hast.

Aber du hast z.B. nicht das Problem, wie es Marco13 in seinem C++ Programm gezeigt hast. Du kannst sofort anhand des Quellcodes entscheiden, ob die Methode doSomething() das macht was sie in A macht, oder das was sie in B macht.


----------



## faetzminator (7. Jul 2009)

Das ist bei Einfachvererbung durchaus so, aber wie sieht das bei mehrfachvererbung aus? Ich weiss, dass dies z.B. in Python möglich ist, und grundsätzlich die Methode der erstdefinierten Klasse verwendet wird. Aber kann man dort explizit auf eine Methode der zweitdefinierten Klasse verwenden? Als Beispiel: B erbt von A1 und A2, ich habe in beiden Klassen foo(String) und bar(int), ich will nun foo() von A1 und bar() von A2 verwenden - was dann?


----------



## _fliX (7. Jul 2009)

Paddelpirat hat gesagt.:


> @_flix
> In dem Fall:
> Es gibt die klassen A,B,C
> B erbt von A und C erbt von B
> ...



kann man das so festhalten, das jeweils immer die letzte "gültige" methode/attribut benutzt wird?


----------



## Leroy42 (7. Jul 2009)

Also als Fazit dessen Allem:

Mehrfachvererbung resultiert in einen grossen Haufen Scheisse! :shock:

(Deswegen gibts also solche Probleme mit gewissen Säugetieren und ähnlichem! )


----------



## SchonWiederFred (7. Jul 2009)

Ariol hat gesagt.:


> Das erstellte Objekt bc ist vom Typ BC, welches zuerst B erbt:


Die "Vererbungsreihenfolge" spielt keine Rolle.


			
				C++ Standard §10.1 (2) hat gesagt.:
			
		

> the order of derivation is not significant except as specified by the semantics of initialization by constructor (12.6.2), cleanup (12.4), and storage layout (9.2, 11.1).


Das gezeigte Programmfragment ist ein Puzzle. Puzzles gibt es in jeder Sprache, aber niemand würde sowas wirklich schreiben und einsetzen.


----------



## SchonWiederFred (7. Jul 2009)

faetzminator hat gesagt.:


> Als Beispiel: B erbt von A1 und A2, ich habe in beiden Klassen foo(String) und bar(int), ich will nun foo() von A1 und bar() von A2 verwenden - was dann?




```
#include <iostream>
#include <string>

struct A1
{
    virtual void foo(std::string const& str)
    {
        std::cout << "foo in A1\n";
    }

    virtual void bar(int x)
    {
        std::cout << "bar in A1\n";
    }
};

struct A2
{
    virtual void foo(std::string const& str)
    {
        std::cout << "foo in A2\n";
    }

    virtual void bar(int x)
    {
        std::cout << "bar in A2\n";
    }
};

struct B : A1, A2
{
};

int main()
{
    B b;
    b.A1::foo("hello");
    b.A2::bar(42);
}
```


----------

