Class Inheritance: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
Line 106: Line 106:
It's a simple concept to understand but not as easy to implement correctly.
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.
When using an external base class the first thing you have to do is declare it in what is termed a 'template' or 'skeleton'. These do NOT affect those classes, they merely tell the compiler how they are constructed.
This tells the game engine that there is a sibling class within the master config that your class is somehow based on.
Stated wrongly, the game engine ill throw a fit if it discovers what-you-say, is not-the-truth. It does this as it is progressively builds the master config
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:
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:


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
// the external 'skeleton'
class externalBaseClass; // declare external base class
class externalBaseClass; // declare external base class
//
class myClass: externalBaseClass // define that you inherit from it
class myClass: externalBaseClass // define that you inherit from it
{
{
Line 119: Line 122:




Now what if you want to access a child class of the base 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:
Now what if you want to access a child class of the base class? At this point, you are accessing the contents of the base class, and thus you need to declare this class s being part of that base class eg a eg a child and it's parent.
 
 


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
class externalBaseClass;
//// the 'template'
class externalCoolClass: externalBaseClass
class externalRootClass
{
{
class externalChildClass;
class externalChildClass;
};
};
class myClass: externalCoolClass
///////////
class myClass: externalRootClass
{
{
class externalChildClass: externalChildClass
class externalChildClass: externalChildClass // import ALL the  values from the oriiginal
{
{
// ...
// ... add, or make, changes
};
};
// ...
// ...
Line 137: Line 143:
</syntaxhighlight>
</syntaxhighlight>


A 'root' class is one that comes from the root of the master config.bin
The above is a primitive example of classes embedded in classes(only one deep). A 'skeleton' tree describes exactly '''where''' the class you want to access is.
Note that a root class can inherit from another root class, thus, you need to:


This might seem complicated at first but you only have to follow these two rules:
class root1;
* If your (child) class is based on an external class, declare the external class first
class root2: root1
* If you open the brackets of an external class, declare the base class of that class as well
{
  etc
};


== Addon loading order ==
== Addon loading order ==

Revision as of 04:41, 17 April 2022

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).

In addition to the master config there are also the

that are sperate from the master config.

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 both Esau and Jacob are child classes of Isaac. They are siblings.

Inheritance

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;
		// ...
	};
};

Either method is stored, as written, in the master config, and either one achieves the same result for any other classes that accesses Isaac.

External base classes

The concept of external base classes only applies to addon configs. For mission configs the import keyword fulfills a similar purpose.

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 declare it in what is termed a 'template' or 'skeleton'. These do NOT affect those classes, they merely tell the compiler how they are constructed. Stated wrongly, the game engine ill throw a fit if it discovers what-you-say, is not-the-truth. It does this as it is progressively builds the master config 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:

// the external 'skeleton'
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? At this point, you are accessing the contents of the base class, and thus you need to declare this class s being part of that base class eg a eg a child and it's parent.


//// the 'template'
class externalRootClass
{
	class externalChildClass;
};
///////////
class myClass: externalRootClass
{
	class externalChildClass: externalChildClass // import ALL the  values from the oriiginal
	{
		// ... add, or make, changes
	};
	// ...
};

A 'root' class is one that comes from the root of the master config.bin The above is a primitive example of classes embedded in classes(only one deep). A 'skeleton' tree describes exactly where the class you want to access is.

Note that a root class can inherit from another root class, thus, you need to:

class root1; class root2: root1 {

  etc

};

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.

The loading order always needs to be defined!

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.

A3_Data_F_Oldman_Loadorder is the last vanilla CfgPatches entry in Arma 3 2.00, so you can put this to overwrite some vanilla configs.

delete

Within configs the delete class keyword is available. It can be used to delete already existing classes. However, classes that other classes derive from cannot be deleted unless the child classes are deleted first.

class Intel
{
    class AttributeCategories
    {
        class Date
        {
            class Attributes
            {
                    delete Fog;//Removes Fog attribute from Eden Editor
            };
        };
    };
};
class Intel 
{
	class Attributes
	{
        class Fog;
		class TimeMultiplier: Fog
		{
			displayName = "Time Multiplier";
			tooltip = "Set the time multiplier";
			//...
		};
        delete Fog;//Will not work since a children of Fog still exists.
	};
};