MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame^] | 1 | KONZEPT |
| 2 | inheritance |
| 3 | |
| 4 | BESCHREIBUNG |
| 5 | Mittels Vererbung kann man das Verhalten und/oder die implementierten |
| 6 | Methoden eines Objektes in ein neues Objekt hineinerben. |
| 7 | |
| 8 | 1. Wozu ist Vererbung gut |
| 9 | 1.1. Erben von Implementationen: Strukturieren von Bibliotheken |
| 10 | Mit Vererbung der Implementation koennen aufeinander aufbauende und gut |
| 11 | wart-/nutzbare Strukturen geschaffen werden: |
| 12 | |
| 13 | /std/thing/description beinhaltet |
| 14 | - wie ein Objekt aussieht/welche Details es gibt |
| 15 | - wie man das Objekt finden/identifizieren kann |
| 16 | /std/thing/moving beinhaltet |
| 17 | - wie man ein Objekt bewegen kann |
| 18 | /std/thing erbt |
| 19 | - /std/thing/description und |
| 20 | - /std/thing/moving |
| 21 | - damit den Code aus beiden Objekten (und noch andere) |
| 22 | |
| 23 | Sowohl thing/description als auch thing/moving sind nicht als |
| 24 | eigenstaendige Objekte sinnvoll nutzbar, sind abstrakt. |
| 25 | |
| 26 | 1.2. Erben von Schnittstellen und Verhalten |
| 27 | Durch das Erben von /std/thing werden Schnittstelle und auch |
| 28 | Verhalten von /std/thing geerbt: |
| 29 | |
| 30 | -- keks.c -- |
| 31 | inherit "/std/thing"; |
| 32 | -- |
| 33 | |
| 34 | Dadurch koennen jetzt andere Objekte, wie NPCs oder Spieler mit dem |
| 35 | Keks-Objekt so interagieren, als wenn es ein /std/thing waere. |
| 36 | |
| 37 | Morgengrauen stellt eine grosse Bibliothek von miteinander sinnvoll |
| 38 | agierenden Objekten unter /std zur Verfuegung, Die dort verfuegbaren |
| 39 | Objekte sind groesstenteils selbsterklaerend, wie /std/npc, |
| 40 | /std/armour oder /std/weapon. |
| 41 | |
| 42 | Das Keks-Objekt muss erweitert werden, wenn es sich vom normalen |
| 43 | Ding unterscheiden soll. Typischerweise geschieht das durch |
| 44 | Ueberschreiben der Initialisierungmethode namens "create". |
| 45 | |
| 46 | 2. Ueberschreiben/Erweitern von Verhalten/Methoden |
| 47 | 2.1. Ueberschreiben |
| 48 | Um das Verhalten von geerbten Methoden zu erweitern, muss diese |
| 49 | ueberschrieben werden: |
| 50 | |
| 51 | -- keks.c -- |
| 52 | ... |
| 53 | void create() { |
| 54 | SetProp(P_NAME, "Keks"); |
| 55 | SetProp(P_GENDER, MALE); |
| 56 | AddId(({"keks"})); |
| 57 | } |
| 58 | -- |
| 59 | |
| 60 | Allerdings wuerde jetzt der normale Code von "create" in /std/thing |
| 61 | nicht mehr ausgefuehrt werden. Mit dem 'scope'-Operator :: wird |
| 62 | innerhalb einer ueberschriebenen Methode auf deren bisherige |
| 63 | Implementation zugegriffen: |
| 64 | |
| 65 | -- keks.c -- |
| 66 | ... |
| 67 | void create() { |
| 68 | ::create(); |
| 69 | SetProp(P_NAME, "Keks"); |
| 70 | SetProp(P_GENDER, MALE); |
| 71 | AddId(({"keks"})); |
| 72 | } |
| 73 | -- |
| 74 | |
| 75 | Auf geerbte globale Variablen kann normal zugegriffen werden, wenn |
| 76 | diese nicht vor direktem Zugriff durch erbende Objekte geschuetzt |
| 77 | wurden. Also in ihrer Sichtbarkeit veraendert wurde. |
| 78 | |
| 79 | Ueberschreiben von Methoden in den davon erbenden Objekten kann durch |
| 80 | das Schluesselwort 'nomask' verboten werden. |
| 81 | |
| 82 | 2.2. Sichtbarkeit von Methoden und Variablen |
| 83 | Es ist moeglich, Methoden und Variablen mit einem Modifikator fuer |
| 84 | ihre Sichtbarkeit zu versehen, der auch bei der Vererbung zum |
| 85 | Tragen kommt: |
| 86 | - 'public' Methoden sind von aussen/innen in Eltern/Kind zugreifbar |
| 87 | - 'protected' Methoden sind nur von innen in Eltern/Kind zugreifbar |
| 88 | - 'private' Methoden sind nur von innen in Eltern zugreifbar |
| 89 | (also nur im definierenden Objekt selbst) |
| 90 | |
| 91 | 2.3 Laufzeit-Polymorphie (vielgestaltes Verhalten) |
| 92 | Methoden werden in LPC immer erst zum Zeitpunkt ihres Aufrufs |
| 93 | gebunden, also nicht schon beim Laden. Beispielsweise koennen |
| 94 | wir unseren Keks essbar machen: |
| 95 | |
| 96 | -- keks.c -- |
| 97 | ... |
| 98 | void create() { |
| 99 | ... |
| 100 | AddCmd("iss&@ID", "action_essen", "Was willst du essen?"); |
| 101 | } |
| 102 | |
| 103 | int action_essen() { |
| 104 | if(this_player()->eat_food(1, 0, |
| 105 | "Du bekommst "+QueryPronoun(WEN)+ |
| 106 | " nicht mehr hineingestopft.\n")>0) { |
| 107 | write("Du isst "+name(WEN,1)+".\n"); |
| 108 | say(this_player()->Name(WER)+" isst "+name(WEN)+".\n"); |
| 109 | remove(); |
| 110 | } |
| 111 | return 1; |
| 112 | } |
| 113 | -- |
| 114 | |
| 115 | und jetzt in einem davon erbenden Kruemelkeks diesen beim Entfernen |
| 116 | im "remove" kruemeln lassen: |
| 117 | |
| 118 | -- kruemelkeks.c -- |
| 119 | inherit "/doc/beispiele/inherit/keks.c"; |
| 120 | ... |
| 121 | varargs int remove(int silent) { |
| 122 | if(!silent && living(environment())) |
| 123 | tell_object(environment(), Name(WER,1)+ |
| 124 | " kruemelt ein letztes Mal.\n"); |
| 125 | return ::remove(silent); |
| 126 | } |
| 127 | -- |
| 128 | |
| 129 | Trotzdem wir "action_essen" nicht modifiziert haben, wird von dieser |
| 130 | Methode in einem Kruemelkeks immer automatisch die aktuelle und |
| 131 | kruemelende "remove" aufgerufen. |
| 132 | |
| 133 | 3. Multiple Inheritance |
| 134 | In LPC ist multiple Vererbung moeglich. Das heisst, man kann von |
| 135 | mehreren Objekten erben. Das kann zu Konflikten fuehren, zum Beispiel |
| 136 | wenn eine Methode in zwei Objekten von denen geerbt wurde vorkommt. |
| 137 | |
| 138 | Diese Konflikte sollte man dann "per Hand" loesen in dem man diese |
| 139 | spezielle Methode ueberschreibt und mittels des scope-Operators die |
| 140 | gewuenschte(n) geerbt(en) Methode(n) aufruft: |
| 141 | |
| 142 | inherit "/std/weapon"; |
| 143 | inherit "/std/lightsource"; |
| 144 | |
| 145 | void create() { |
| 146 | weapon::create(); |
| 147 | lightsource::create(); |
| 148 | ... |
| 149 | } |
| 150 | |
| 151 | void init() { |
| 152 | weapon::init(); |
| 153 | lightsource::init(); |
| 154 | // oder sehr generell und unkontrolliert: |
| 155 | // "*"::init(); |
| 156 | } |
| 157 | |
| 158 | Schwerwiegende Konflikte koennen auftreten, wenn eine gleichnamige |
| 159 | Variable aus verschiedenen Objekten geerbt wird. Die Variablen |
| 160 | existieren im letztlich erbenden Objekt zweimal und die verschiedenen |
| 161 | geerbten Methoden greifen auf ihre jeweilige Variante zu. |
| 162 | |
| 163 | Beispiel ist die sog. "Masche" oder der "Diamond of Death": |
| 164 | |
| 165 | A (Ursprungsobjekt mit globaler Variable x) |
| 166 | / \ |
| 167 | B C (B, C erben von A und manipulieren beide x) |
| 168 | \ / |
| 169 | D (D erbt von B und A) |
| 170 | |
| 171 | Mit dem Schluesselwort 'virtual' kann die Doppelung beim Erben |
| 172 | in B und C unterbunden werden. |
| 173 | |
| 174 | SIEHE AUCH: |
| 175 | inherit |
| 176 | private, protected, public, nomask |
| 177 | virtual |
| 178 | objekte, oop |
| 179 | /doc/beispiele/inherit |
| 180 | |
| 181 | 2.Feb 2008 Gloinson |