Class Inheritance: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
mNo edit summary
No edit summary
Line 1: Line 1:
this is not ready for prime time.
Inheriting classes within the config is a concept that can easily go wrong. The purpose of this document is to clarify the cause of some common errors and contains instructions on how to resolve these mistakes.
=terms=
=Terms=
*'''config''' is a config.cpp or config.bin. It is NOT a model.cfg
*A '''config''' is a config.cpp or config.bin file that is loaded during the game start. It is does not refer to a [[Model Config]].
*'''master''' config.bin is the in-game, one and only config built from all other configs
*The '''master''' config is the in-game one and only config built from all other configs. This includes both the base game configs as well as addon configs. It can be viewed through the Splendid Config Viewer.
*'''bin''' config.bin is the father of all other config.bins. It forms the first state of the master config.bin
*'''bin''' or '''config.bin''' is the father of all other configs. It forms the first state of the master config.bin and consists of the base game configs.
*'''child''' config.bins are added to the master config.bin  
*'''child configs''' are added on top of the config.bin. The order in which they get added is defined by the requiredAddons array within the CfgPatches (see [[#Addon_loading_order|addon loading order]]).
=externs=


externs are a simple concept to understand, and a difficult thing to implement correctly.


simply stated, an extern is telling both the compiler and later, the game engine, that there is a class entry _at this indent_ in the master config.bin
=Basic config concepts=
The config is a hierarchical structure based on classes that provides almost all information necessary for the game. Objects, their behaviour, user interface elements and even which functions to run on game start are defined through the config.


there may, or may not be an inheritence association with an extern class, but it cannot be declared in the above way and isnot necessary to do so
Classes can contain either child classes (see below) or contain properties. Properties work similar to script variables, they have a name and a value. However unlike script variables properties can only have either number or string values, or (one- or multidimensional) arrays of number or string values.


1) IF  you are not using any embedded classes of that extern
==Parent and child classes==
2) you have properly declared via requiredaddons which config this extern is actually in
Due to the hierarchical nature of the config, classes can have '''parent''', '''child''' and '''sibling''' classes:


1)
class Isaac {
    class extern;
    class Esau {
    class thing:extern
        gender = "male";
    {
        firstborn = 1;
      class one {...} /is fine it's your class, not the externs
        ...
    }
    };
    class Jacob {
        gender = "male";
        firstborn = 0;
        ...
    };
};


    class extern;
    class thing:extern
    {
      class one:one {...} //is not fine you are stating (in most cases) there is a class one ALSO in the extern that you wish to inherit from
    }


==engine build==
In this example, the parent class of Esau is Isaac, Esau and Jacob are child classes of Isaac, and Jacob is a sibling class of Esau.


class extern;  causes the engine to create an empty class at that indent _if at the time of encounter_, there is no class in the master bin
==Inherition==
A class can inherit properties from sibling classes by defining it as a base class. This means that all properties of that base class will also exist within your class and, unless you overwrite them, will have the same values as in the base class. This is extremly useful for quickly writing sibling classes that share properties, or to build a class on top of another class that has the same properties with only minor value changes.


later, when the 'real' class is discovered, it replaces that empty class
Taking the example from above we can either create a common ''ChildMaleBase'' base class:


if the 'real' class actually has an inheritance, you are in trouble. the engine will complain
class Isaac {
    class ChildMaleBase {
        gender = "male";
    };
    class Esau: ChildMaleBase {
        firstborn = 1;
        ...
    };
    class Jacob: ChildMaleBase {
        firstborn = 0;
        ...
    };
};




Or we can use ''Esau'' as a base class for ''Jacob'' and overwrite the ''firstborn'' property:


=other=
class Isaac {
    class Esau {
        gender = "male";
        firstborn = 1;
        ...
    };
    class Jacob: Esau {
        firstborn = 0;
        ...
    };
};


i am just getting some ideas down on how to explain


*the necessity of requiredAddons[]=  aka the pbo loading order
Both will have the same result in the master config, but note that in the latter example ''Jacob'' is dependant on ''Esau'' which is logically not correct - one can exist without the other. Especially when having more than one sibling class, you should consider creating a base class for good practice.
*the difference between config tree declarations vs their bodies
*what class blah{}; actually does (vs blah:blah{}) and how to implement it properly
*how ofp behaves differently in class trees and what access= is all about


---------


Class Inheritance refers to the way in which classes are superimposed onto each other.
=External base classes=
Especially when writing the config for a new vehicle or changing the config of an existing vehicle, you will sooner or later come on contact with external base classes. External base classes are simply base classes that you did ''not define within your own config'' but were defined either by the base game or another addon.


It's a simple concept to understand but not as easy to implement correctly.


class Base
When using an external base class the first thing you have to do is declaring it. This tells the game engine that there is a sibling class within the master config that your class is somehow based on. It is only important to declare the base class of your class, there is no need to declare the base class of the base class and so on:
{
 
  a base class containing (probably) embedded classes
class externalBaseClass;                   //declare external base class
  class EmbeddedClass
class myClass: externalBaseClass {         //define that you inherit from it
  {
    ...                                   //start using it
  ...
  };
  class InheritedClass:EmbeddedClass
  {
  ...
  };
  };
  };


The above is the creation of the class with real values


example
Now what if you want to access a child class of the base class of your own class? At this point, you are accessing the contents of the base class, and thus you need to declare the base class of the base class as well:


  class Vehicles
  class externalBaseClass;
  {
  class externalCoolClass: externalBaseClass {
  class Vehicle{......};
    class externalChildClass;
  class Car:Vehicle{......};
};
  class Truck:Car{......};
class myClass: externalCoolClass {
    class externalChildClass: externalChildClass {
        ...
    };
    ...
  };
  };


Inheritance skeleton


The engine needs to know how above is constructed when inheriting from it
This might seem complicated at first but you only have to follow these two rules:
*If your (child) class is based on an external class, declare the external class first
*If you open the brackets of an external class, declare the base class of that class as well




if you aren't altering embedded classes:
=Addon loading order=
When you are using external base classes it is extremly important to define what addons your addon depends on, or in other words, which external base classes need to be already loaded when your config gets loaded. '''Not defining the load order will guarantee you to end up in a world of pain and horror.'''


class Car;
Defining which addons are required by your config is easily done through the ''CfgPatches'':
 
  class CfgPatches {
altering things in truck
    class MyAddon {
 
        ...
  class Car;
        requiredAddons[] = {"ExternalAddonA", "ExternalAddonB", ...};
class Truck:Car{....};
        ...
 
    };
class anything{}; wipes out previous. NOTE however that requiredAddons is needed
};
This ensures that whatever changes you made or whatever classes based on some other classes you defined are applied on top of the external addons child config. Without this there is no guarantee that your config gets applied correctly.


[[Category:ArmA: Addon Configuration]]
[[Category:ArmA: Addon Configuration]]

Revision as of 04:46, 7 January 2016

Inheriting classes within the config is a concept that can easily go wrong. The purpose of this document is to clarify the cause of some common errors and contains instructions on how to resolve these mistakes.

Terms

  • A config is a config.cpp or config.bin file that is loaded during the game start. It is does not refer to a Model Config.
  • The master config is the in-game one and only config built from all other configs. This includes both the base game configs as well as addon configs. It can be viewed through the Splendid Config Viewer.
  • bin or config.bin is the father of all other configs. It forms the first state of the master config.bin and consists of the base game configs.
  • child configs are added on top of the config.bin. The order in which they get added is defined by the requiredAddons array within the CfgPatches (see addon loading order).


Basic config concepts

The config is a hierarchical structure based on classes that provides almost all information necessary for the game. Objects, their behaviour, user interface elements and even which functions to run on game start are defined through the config.

Classes can contain either child classes (see below) or contain properties. Properties work similar to script variables, they have a name and a value. However unlike script variables properties can only have either number or string values, or (one- or multidimensional) arrays of number or string values.

Parent and child classes

Due to the hierarchical nature of the config, classes can have parent, child and sibling classes:

class Isaac {
    class Esau {
        gender = "male";
        firstborn = 1;
        ...
    };
    class Jacob {
        gender = "male";
        firstborn = 0;
        ...
    };
};


In this example, the parent class of Esau is Isaac, Esau and Jacob are child classes of Isaac, and Jacob is a sibling class of Esau.

Inherition

A class can inherit properties from sibling classes by defining it as a base class. This means that all properties of that base class will also exist within your class and, unless you overwrite them, will have the same values as in the base class. This is extremly useful for quickly writing sibling classes that share properties, or to build a class on top of another class that has the same properties with only minor value changes.

Taking the example from above we can either create a common ChildMaleBase base class:

class Isaac {
    class ChildMaleBase {
        gender = "male";
    };
    class Esau: ChildMaleBase {
        firstborn = 1;
        ...
    };
    class Jacob: ChildMaleBase {
        firstborn = 0;
        ...
    };
};


Or we can use Esau as a base class for Jacob and overwrite the firstborn property:

class Isaac {
    class Esau {
        gender = "male";
        firstborn = 1;
        ...
    };
    class Jacob: Esau {
        firstborn = 0;
        ...
    };
};


Both will have the same result in the master config, but note that in the latter example Jacob is dependant on Esau which is logically not correct - one can exist without the other. Especially when having more than one sibling class, you should consider creating a base class for good practice.


External base classes

Especially when writing the config for a new vehicle or changing the config of an existing vehicle, you will sooner or later come on contact with external base classes. External base classes are simply base classes that you did not define within your own config but were defined either by the base game or another addon.

It's a simple concept to understand but not as easy to implement correctly.

When using an external base class the first thing you have to do is declaring it. This tells the game engine that there is a sibling class within the master config that your class is somehow based on. It is only important to declare the base class of your class, there is no need to declare the base class of the base class and so on:

class externalBaseClass;                   //declare external base class
class myClass: externalBaseClass {         //define that you inherit from it
    ...                                    //start using it
};


Now what if you want to access a child class of the base class of your own class? At this point, you are accessing the contents of the base class, and thus you need to declare the base class of the base class as well:

class externalBaseClass;
class externalCoolClass: externalBaseClass {
    class externalChildClass;
};
class myClass: externalCoolClass {
    class externalChildClass: externalChildClass {
        ...
    };
    ...
};


This might seem complicated at first but you only have to follow these two rules:

  • If your (child) class is based on an external class, declare the external class first
  • If you open the brackets of an external class, declare the base class of that class as well


Addon loading order

When you are using external base classes it is extremly important to define what addons your addon depends on, or in other words, which external base classes need to be already loaded when your config gets loaded. Not defining the load order will guarantee you to end up in a world of pain and horror.

Defining which addons are required by your config is easily done through the CfgPatches:

class CfgPatches {
    class MyAddon {
        ...
        requiredAddons[] = {"ExternalAddonA", "ExternalAddonB", ...};
        ...
    };
};

This ensures that whatever changes you made or whatever classes based on some other classes you defined are applied on top of the external addons child config. Without this there is no guarantee that your config gets applied correctly.