Object Oriented Programming Advanced Usage – Arma Reforger
Lou Montana (talk | contribs) (Add modded section) |
Lou Montana (talk | contribs) (Add modding order example) |
||
(11 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
{{TOC|side}} | {{TOC|side}} | ||
{{Feature|informative|This guideline requires the understanding of | {{Feature|informative|This guideline requires the understanding of {{Link|Arma Reforger:Object Oriented Programming Basics}}.}} | ||
Line 7: | Line 7: | ||
Casting is the act of "presenting" a value as another type. For example, if a class hierarchy is {{hl|Animal > Dog > Cocker}}, a dog is an animal, a cocker is a dog (that is an animal), but a dog is not especially a cocker. | Casting is the act of "presenting" a value as another type. For example, if a class hierarchy is {{hl|Animal > Dog > Cocker}}, a dog is an animal, a cocker is a dog (that is an animal), but a dog is not especially a cocker. | ||
< | <enforce> | ||
class Animal {} | class Animal {} | ||
class Dog : Animal {} | class Dog : Animal {} | ||
class Cocker : Dog {} | class Cocker : Dog {} | ||
class Labrador : Dog {} | class Labrador : Dog {} | ||
</ | </enforce> | ||
=== Upcasting === | === Upcasting === | ||
Upcasting means seeing the class as one of its parents: | Upcasting means seeing the class as one of its parents: | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 23: | Line 23: | ||
Animal animal = cocker; // OK, as a cocker is an animal | Animal animal = cocker; // OK, as a cocker is an animal | ||
string sentence = cocker; // error: cocker does -not- inherit from string | string sentence = cocker; // error: cocker does -not- inherit from string | ||
} | } | ||
</ | </enforce> | ||
=== Downcasting === | === Downcasting === | ||
Downcasting means seeing a parent class as a specific child - this must be done by manually casting: | Downcasting means seeing a parent class as a specific child - this must be done by manually casting: | ||
< | <enforce> | ||
void Method(Dog dog) | void Method(Dog dog) | ||
{ | { | ||
Line 35: | Line 35: | ||
Cocker cocker2 = Cocker.Cast(dog); // OK: manual casting tells the code "the developer knows what he is doing" | Cocker cocker2 = Cocker.Cast(dog); // OK: manual casting tells the code "the developer knows what he is doing" | ||
// if 'dog' is not castable as a Cocker, null is returned - the code does not crash | // if 'dog' is not castable as a Cocker, null is returned - the code does not crash | ||
} | } | ||
</ | </enforce> | ||
=== Manual Casting === | === Manual Casting === | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 50: | Line 47: | ||
string value3 = "result = " + (bool)value2; // "result = true", as a non-zero integer is true when casted to bool | string value3 = "result = " + (bool)value2; // "result = true", as a non-zero integer is true when casted to bool | ||
} | } | ||
</ | </enforce> | ||
Line 59: | Line 56: | ||
{{Feature|informative|The generic type is by convention declared by the {{hl|T}} letter.}} | {{Feature|informative|The generic type is by convention declared by the {{hl|T}} letter.}} | ||
< | <enforce> | ||
// template class Item with generic type T | // template class Item with generic type T | ||
class Item<Class T> | class Item<Class T> | ||
Line 84: | Line 81: | ||
Print(m_data); | Print(m_data); | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 93: | Line 90: | ||
Item<int> intItem = new Item<int>(72); // template class Item declared with type "int". In Item<int> class, all Ts are substituted with 'int' | Item<int> intItem = new Item<int>(72); // template class Item declared with type "int". In Item<int> class, all Ts are substituted with 'int' | ||
stringItem.PrintData(); // prints "m_data = 'Hello!'" | |||
intItem.PrintData(); // prints "m_data = 72" | |||
} | } | ||
</ | </enforce> | ||
Line 102: | Line 99: | ||
A mod can inherit/replace an existing class with the use of the {{hl|modded}} keyword.<br> | A mod can inherit/replace an existing class with the use of the {{hl|modded}} keyword.<br> | ||
It is used to inject inherited class into class hierarchy without modifying other scripts (especially suitable in modding). A modded class behaves like a class inherited from the original class (one can use {{hl|super}} to access the original class). When a modded class is declared, the modded class will be instanced instead of the original class. Only classes within the same module can be modded (to mod a class in e.g {{hl|GameLib}} module, the modded class has to be placed in the {{hl|GameLib}} module). | It is used to inject inherited class into class hierarchy without modifying other scripts (especially suitable in modding). | ||
A modded class behaves like a class inherited from the original class (one can use {{hl|{{Link|Arma Reforger:Object Oriented Programming Basics#super|super}}}} to access the original class) but also allows '''{{hl|private}}''' methods and functions access and modification. | |||
When a modded class is declared, the modded class will be instanced instead of the original class. | |||
{{Feature|important|Only classes within the same module can be modded (to mod a class in e.g {{hl|GameLib}} module, the modded class has to be placed in the {{hl|GameLib}} module).}} | |||
< | <enforce> | ||
// game | // game | ||
class A | class A | ||
{ | { | ||
private string m_sPrivateString = "something said"; | |||
void Say() | void Say() | ||
{ | { | ||
Print(" | Print("original Say method"); | ||
Print(m_sPrivateString); | |||
} | } | ||
}; | } | ||
void Test() | |||
{ | |||
A a = new A(); // "class A" is instanced | |||
a.Say(); // prints "original Say method" then "something said" | |||
} | |||
// mod | // mod | ||
modded class A // this class automatically inherits from the original class A | modded class A // this class automatically inherits from the original class A | ||
{ | { | ||
void Say() | override void Say() | ||
{ | { | ||
Print(" | m_sPrivateString = "modded said"; | ||
Print("modded Say method"); | |||
super.Say(); | super.Say(); | ||
} | } | ||
} | } | ||
void | void TestModded() | ||
{ | { | ||
A a = new A(); // "modded class A" is instanced | A a = new A(); // "modded class A" is instanced | ||
a.Say(); // prints | a.Say(); // prints "modded Say method" then "original Say method" and "modded said" | ||
} | |||
</enforce> | |||
=== Precedence === | |||
Multiple mods can edit the same class if loaded together. In such case, vanilla class gets modded in order by mod1, mod2, mod3. | |||
Mod loading order is defined by dependency (if mod2 requires mod1, mod1 is loaded first) - if no dependencies are involved, order is not guaranteed. | |||
{| class="valign-top" style="width: 100%" | |||
! Vanilla | |||
! Mod 1 | |||
! Mod 2 | |||
|- | |||
| | |||
<enforce> | |||
class SCR_ExampleClass | |||
{ | |||
string GetMessage() | |||
{ | |||
return "Vanilla message"; | |||
} | |||
} | } | ||
</ | </enforce> | ||
| | |||
<enforce> | |||
modded class SCR_ExampleClass | |||
{ | |||
override string GetMessage() | |||
{ | |||
return super.GetMessage() + ", Mod A"; | |||
} | |||
} | |||
</enforce> | |||
| | |||
<enforce> | |||
modded class SCR_ExampleClass | |||
{ | |||
override string GetMessage() | |||
{ | |||
return super.GetMessage() + ", Mod B"; | |||
} | |||
} | |||
</enforce> | |||
|} | |||
{| style="width: 100%" | |||
| If Mod B requires Mod A, the load order will be Vanilla > Mod A > Mod B. | |||
| <enforce>instance.GetMessage(); // Vanilla message, Mod A, Mod B</enforce> | |||
|- | |||
| If Mod A requires Mod B, the load order will be Vanilla > Mod B > Mod A (obviously). | |||
| <enforce>instance.GetMessage(); // Vanilla message, Mod B, Mod A</enforce> | |||
|- | |||
| If no dependencies are defined between mods, the load order is arbitrary. | |||
| <enforce> | |||
// can be one of | |||
instance.GetMessage(); // Vanilla message, Mod A, Mod B | |||
// or | |||
instance.GetMessage(); // Vanilla message, Mod B, Mod A | |||
</enforce> | |||
|} | |||
{{GameCategory|armaR|Modding|Guidelines | {{GameCategory|armaR|Modding|Scripting|Guidelines}} |
Latest revision as of 10:23, 11 April 2025
Casting
Casting is the act of "presenting" a value as another type. For example, if a class hierarchy is Animal > Dog > Cocker, a dog is an animal, a cocker is a dog (that is an animal), but a dog is not especially a cocker.
Upcasting
Upcasting means seeing the class as one of its parents:
Downcasting
Downcasting means seeing a parent class as a specific child - this must be done by manually casting:
Manual Casting
Template
A template is a class that allows a generic management for multiple types. Its methods cannot assume anything about the type.
Modding
A mod can inherit/replace an existing class with the use of the modded keyword.
It is used to inject inherited class into class hierarchy without modifying other scripts (especially suitable in modding).
A modded class behaves like a class inherited from the original class (one can use super to access the original class) but also allows private methods and functions access and modification.
When a modded class is declared, the modded class will be instanced instead of the original class.
Precedence
Multiple mods can edit the same class if loaded together. In such case, vanilla class gets modded in order by mod1, mod2, mod3. Mod loading order is defined by dependency (if mod2 requires mod1, mod1 is loaded first) - if no dependencies are involved, order is not guaranteed.
Vanilla | Mod 1 | Mod 2 |
---|---|---|
|
modded class SCR_ExampleClass
{
override string GetMessage()
{
return super.GetMessage() + ", Mod A";
}
} |
modded class SCR_ExampleClass
{
override string GetMessage()
{
return super.GetMessage() + ", Mod B";
}
} |
If Mod B requires Mod A, the load order will be Vanilla > Mod A > Mod B. | instance.GetMessage(); // Vanilla message, Mod A, Mod B |
If Mod A requires Mod B, the load order will be Vanilla > Mod B > Mod A (obviously). | instance.GetMessage(); // Vanilla message, Mod B, Mod A |
If no dependencies are defined between mods, the load order is arbitrary. | // can be one of
instance.GetMessage(); // Vanilla message, Mod A, Mod B
// or
instance.GetMessage(); // Vanilla message, Mod B, Mod A |