blob: 23fb804d8e8e3a02597a18f4424cf6d09c2e9269 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001KONZEPT
2 inheritance
3
4BESCHREIBUNG
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
174SIEHE AUCH:
175 inherit
176 private, protected, public, nomask
177 virtual
178 objekte, oop
179 /doc/beispiele/inherit
180
1812.Feb 2008 Gloinson