C++ Question Splitting a monolithic project into multiple files

N_Molson

Addon Developer
Addon Developer
Donator
Joined
Mar 5, 2010
Messages
9,995
Reaction score
4,419
Points
203
Location
Toulouse
Hi, :hello:

So I've decided myself to grab the bull by the horns and attack the delicate matter of classes interdependancy.

(Of course) I'm encountering (expected) difficulties. In the following example I'm trying to extract the "guidance" program from "main.cpp" to a "guidance.cpp". "Sigma_Stg1.h" is the name of the main header.

First I need to create a "guidance.h" header file. Well. So here it is :

Code:
#ifndef __GUIDANCE_H
#define __GUIDANCE_H

#include    "Sigma_Stg1.h"
#include    "Orbitersdk.h"

class Guidance
{
public:
    Guidance(void);
    ~Guidance(void);
    void GuidanceProgram();
private:

};

#endif

That compiles without errors. Well again.

Troubles arise from "Guidance.cpp", that hits the 100 errors mark. Seems it doesn't recognize variables or even Orbiter functions. Here's "Guidance.cpp" :

Code:
#include    "math.h"
#include    "stdio.h"
#include    "Guidance.h"

#define ORBITER_MODULE

// --------------------------------------------------------------
// Module initialisation
// --------------------------------------------------------------
DLLCLBK void InitModule (HINSTANCE hModule)
{
}

// --------------------------------------------------------------
// Module cleanup
// --------------------------------------------------------------
DLLCLBK void ExitModule (HINSTANCE hModule)
{
}

void Guidance::GuidanceProgram()
{
     ... blah blah blah...
};

So, if someone can help me to get on track, thanks a lot. I know it is a difficult matter difficult to explain, but I absolutely need to get there to finish my projects. :tiphat:
 
Would need to see the errors to tell you more, except some minor causes for warnings (No semicolon after a "}" required ), I can't see much special there. #ORBITER_MODULE should exist of course in only one cpp file... do you have it in main.cpp as well? Same for Init- and ExitModule, they also must exist exactly one time.

---------- Post added at 12:59 PM ---------- Previous post was at 12:58 PM ----------

Instead of the old C header guards (#ifndef.... #endif) I recommend using the modern version of "#pragma once" for C++ projects. You will never find a C++ compiler that does not understand that pragma today.
 
I removed the "ORBITER MODULE" and "Init/Exit module" declarations ; as they are in the main cpp

The errors are about some Orbiter functions and all my variables (that are declared in the main header and initialized in the main cpp) :

HTML:
1>------ Début de la génération : Projet : Sigma, Configuration : Debug Win32 ------
1>Compilation en cours...
1>Guidance.cpp
1>.\Guidance.cpp(17) : error C3861: 'GetAngularVel' : identificateur introuvable
1>.\Guidance.cpp(26) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(28) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(31) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(31) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(33) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(33) : error C2065: 'g_tgt1' : identificateur non déclaré
1>.\Guidance.cpp(33) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(35) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(35) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(37) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(37) : error C2065: 'g_tgt1' : identificateur non déclaré
1>.\Guidance.cpp(37) : error C2065: 'g_tgt2' : identificateur non déclaré
1>.\Guidance.cpp(37) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(37) : error C2065: 'g_tgt1' : identificateur non déclaré
1>.\Guidance.cpp(39) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(39) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(41) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(41) : error C2065: 'g_tgt2' : identificateur non déclaré
1>.\Guidance.cpp(41) : error C2065: 'g_tgt4' : identificateur non déclaré
1>.\Guidance.cpp(41) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(41) : error C2065: 'g_tgt2' : identificateur non déclaré
1>.\Guidance.cpp(43) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(43) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(45) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(45) : error C2065: 'g_tgt3' : identificateur non déclaré
1>.\Guidance.cpp(45) : error C2065: 'g_tgt5' : identificateur non déclaré
1>.\Guidance.cpp(45) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(45) : error C2065: 'g_tgt3' : identificateur non déclaré
1>.\Guidance.cpp(47) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(47) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(49) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(49) : error C2065: 'g_tgt4' : identificateur non déclaré
1>.\Guidance.cpp(49) : error C2065: 'g_tgt5' : identificateur non déclaré
1>.\Guidance.cpp(49) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(49) : error C2065: 'g_tgt4' : identificateur non déclaré
1>.\Guidance.cpp(52) : error C2065: 'FailType' : identificateur non déclaré
1>.\Guidance.cpp(54) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(54) : error C2065: 'r3' : identificateur non déclaré
1>.\Guidance.cpp(56) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(56) : error C2065: 'r7' : identificateur non déclaré
1>.\Guidance.cpp(62) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(64) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(64) : error C2065: 'PvelMax' : identificateur non déclaré
1>.\Guidance.cpp(64) : error C2065: 'PvelMax' : identificateur non déclaré
1>.\Guidance.cpp(64) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(69) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(69) : error C2065: 'PvelMax' : identificateur non déclaré
1>.\Guidance.cpp(69) : error C2065: 'PvelMax' : identificateur non déclaré
1>.\Guidance.cpp(69) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(76) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(79) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(79) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(79) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(79) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(81) : error C2065: 'PitchCoeff' : identificateur non déclaré
1>.\Guidance.cpp(82) : error C2065: 'PvelMax' : identificateur non déclaré
1>.\Guidance.cpp(84) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(84) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(84) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(84) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(86) : error C2065: 'PitchCoeff' : identificateur non déclaré
1>.\Guidance.cpp(87) : error C2065: 'PvelMax' : identificateur non déclaré
1>.\Guidance.cpp(89) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(89) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(89) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(89) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(91) : error C2065: 'PitchCoeff' : identificateur non déclaré
1>.\Guidance.cpp(92) : error C2065: 'PvelMax' : identificateur non déclaré
1>.\Guidance.cpp(94) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(94) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(94) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(94) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(96) : error C2065: 'PitchCoeff' : identificateur non déclaré
1>.\Guidance.cpp(97) : error C2065: 'PvelMax' : identificateur non déclaré
1>.\Guidance.cpp(99) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(99) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(99) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(99) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(101) : error C2065: 'PitchCoeff' : identificateur non déclaré
1>.\Guidance.cpp(102) : error C2065: 'PvelMax' : identificateur non déclaré
1>.\Guidance.cpp(104) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(104) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(104) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(104) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(106) : error C2065: 'PitchCoeff' : identificateur non déclaré
1>.\Guidance.cpp(107) : error C2065: 'PvelMax' : identificateur non déclaré
1>.\Guidance.cpp(109) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(109) : error C2065: 'Ptarget' : identificateur non déclaré
1>.\Guidance.cpp(109) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(109) : error C3861: 'GetPitch' : identificateur introuvable
1>.\Guidance.cpp(111) : error C2065: 'PitchCoeff' : identificateur non déclaré
1>.\Guidance.cpp(112) : error C2065: 'PvelMax' : identificateur non déclaré
1>.\Guidance.cpp(122) : error C2065: 'ControlLevel' : identificateur non déclaré
1>.\Guidance.cpp(122) : error C2228: la partie gauche de '.x' doit avoir un class/struct/union
1>        le type est ''unknown-type''
1>.\Guidance.cpp(129) : error C2065: 'ControlLevel' : identificateur non déclaré
1>.\Guidance.cpp(129) : error C2228: la partie gauche de '.x' doit avoir un class/struct/union
1>        le type est ''unknown-type''
1>.\Guidance.cpp(135) : error C2065: 'Ytarget' : identificateur non déclaré
1>.\Guidance.cpp(135) : error C2065: 'Azimuth' : identificateur non déclaré
1>.\Guidance.cpp(137) : error C2065: 'FailType' : identificateur non déclaré
1>.\Guidance.cpp(139) : error C2065: 'MET' : identificateur non déclaré
1>.\Guidance.cpp(139) : fatal error C1003: le nombre d'erreurs est supérieur à 100 ; arrêt de la compilation
1>Le journal de génération a été enregistré à l'emplacement "file://g:\Orbiter 2010 P1 - Main\Orbitersdk\samples\Sigma_Stage1\Debug\BuildLog.htm"
1>Sigma - 102 erreur(s), 0 avertissement(s)
========== Génération : 0 a réussi, 1 a échoué, 0 mis à jour, 0 a été ignoré ==========


---------- Post added at 11:09 AM ---------- Previous post was at 11:03 AM ----------

Using #pragma once (seen that in a lot of samples) gives me a few additionnal errors :

Code:
#pragma once

#include	"Sigma_Stg1.h"
#include	"Orbitersdk.h"

class Guidance
{
public:
	Guidance(void);
	~Guidance(void);
	void GuidanceProgram();
private:

}

HTML:
1>.\Guidance.cpp(5) : error C2628: 'Guidance' suivi de 'void' n'est pas conforme (n'auriez-vous pas oublié un ';' ?)
1>.\Guidance.cpp(6) : error C2556: 'Guidance Guidance::GuidanceProgram(void)' : la fonction surchargée ne diffère que par le type de retour de 'void Guidance::GuidanceProgram(void)'
1>        g:\orbiter 2010 p1 - main\orbitersdk\samples\sigma_stage1\Guidance.h(11) : voir la déclaration de 'Guidance::GuidanceProgram'
1>.\Guidance.cpp(6) : error C2371: 'Guidance::GuidanceProgram' : redéfinition ; types de base différents
1>        g:\orbiter 2010 p1 - main\orbitersdk\samples\sigma_stage1\Guidance.h(11) : voir la déclaration de 'Guidance::GuidanceProgram'
 
Troubles arise from "Guidance.cpp", that hits the 100 errors mark. Seems it doesn't recognize variables or even Orbiter functions. Here's "Guidance.cpp" :

A bit more code and the build log would be helpful.

One thing seems odd in what I can see but shouldn't cause an error, and another thing comes to mind from how this class came into existance.

First, I'm wondering what the inclusion of Orbitersdk.h is doing here in the first place. If I assume correctly, then Sigma_Stg1.h is the header of your vessel class, and orbitersdk.h will be included there. As long as you're including Sigma_Stg1.h here, you don't need to include orbitersdk.h again.


Second, What I can currently think might be the source of the errors is that there could be references to vessel variables and functions in there that have not been changed. Note that Guidance is now its own class, so it cannot access any private members of your vessel (which it most likely did when it was still a member of your vessel subclass), nor can it call any functions without having a pointer to the vessel.

Preferably, a private member of Guidance should be a pointer to the vessel, like
Code:
myClass *vessel;

Pass the pointer to guidance when it is initialised by your vessel.
Then you can access public functions, wheather Orbiter API or specific to your subclass, by using the pointer, e.g. vessel->GetName() or whatever.

That is assuming that this is the problem, which is impossible to tell by the code you provided.

EDIT:
I was ninja'd by your error log, and it confirms my suspicion.

For what it's worth, guidance is probably a pretty integrated part of your vessel. It might make sense to not make it its own class but just move all the functions to their own cpp file for better overview (you do not have to make something its own class to put code of it into different cpp files. Indeed, it is very much advisable for larger classes to distribute the functions thematically into several cpp files. IMS currently uses 5 cpp files for its main class, and it's not enough. I'll have some cleaning up to do to make the thing readable to the uninitiated...)
 
Last edited:
I think you've hit the spot.

One thing is that the variables used in "main2.h" and "main2.cpp" (renamed for simplicity sake) are declared in the "private" section of the class. So I guess they are restricted to the "SigmaStg1" vessel class. Is there any way I can overcome this ?

In "myClass *vessel;", should "myClass" = "Guidance" and *vessel = *SigmaStg1 ?

Here's "main2.h", if it can help :
Code:
#ifndef __MAIN2_H
#define __MAIN2_H

#include "orbitersdk.h"

// ==============================================================
// Some vessel parameters
// ==============================================================
const double  PB_SIZE       = 10;             // mean radius [m]
const VECTOR3 PB_RD         = {0.025,0.025,0.02};//{0.05,0.1,0.05};  // rotation drag coefficients
const double SPD = 0.5;

THRUSTER_HANDLE th_bolt1[1], th_bolt2[1];

// ==============================================================
// Sigma Stg1 class interface
// ==============================================================

class Sigma_Stage1: public VESSEL3 {
	friend class Guidance;
public:
	Sigma_Stage1 (OBJHANDLE hVessel, int flightmodel);
	~Sigma_Stage1 ();
	void clbkSetClassCaps (FILEHANDLE cfg);
	void clbkPostStep(double simt, double simdt, double mjd);
	bool clbkDrawHUD (int mode, const HUDPAINTSPEC *hps, oapi::Sketchpad *skp);
	void clbkSaveState(FILEHANDLE scn);
	void clbkLoadStateEx (FILEHANDLE scn, void *status);
	void DefineAnimations(void);
	void SpawnObject(char* classname, char* ext, VECTOR3 ofs);
	void clbkPostCreation (void);
	int clbkConsumeBufferedKey(DWORD key, bool down, char *kstate);

	PROPELLANT_HANDLE hpr, ph_solid, h_B1ph, h_B2ph, ph_acs;
	THRUSTER_HANDLE th_main[1], th_booster[2], th_rcs[14], th_att_down[3], th_att_up[3], th_att_right[3], th_att_left[3], th_lin_fwd[4], th_att_bankleft[3], th_att_bankright[3], th_srbmain1[1], th_srbmain2[1];
	THRUSTER_HANDLE th_dummy[1];
	ATTACHMENTHANDLE ah_booster1, ah_booster2, ah_stage2, ah_child_bstr1, ah_child_bstr2, ah_launchpad;
	OBJHANDLE h_stage2;
	PSTREAM_HANDLE srb_exhaust;

private:
	int done00, done01, done02, done03, done11, done12, done13, done14, done15, done16, done17;
	bool done04, done05, done06, done07, done08, done09, done10;
	int range;
	int camera;
	int lowest;
	int highest;
	int Trigger;
	int loop;
	unsigned int r, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10;
	int FailStep;
	int FailType;
	int countdown;
	int MyID;
	double stg1_EmptyMass;
	double stg2_mass;
	double MET, MET0, BT0, BT, BT2;
	double PvelMax;
	double YvelMax;
	double BvelMax;
	double Ptarget;
	double Ytarget;
	double Btarget;
	double rollV_1;
	double PitchCoeff;
	double YawCoeff;
	double Blevel;
	double Thrust;
	double lvl;
	double lvl2;
	double lvl3;
	double lvl4;
	double lvl5;
	double lvl6;
	double lvl7;
	double SSME_ex;
	double Azimuth;
	double BstrThr;
	double g_tgt1, g_tgt2, g_tgt3, g_tgt4, g_tgt5;
	double reliability;
	double avel_x_1;
	double avel_y_1;
	double avel_z_1;
	unsigned int safety;

	double pitch_proc, yr_proc;
	double pitch_angle, yr_angle;
	double bpitch_proc, byr_proc;
	double bpitch_angle, byr_angle;
	double b1yr_angle, b2yr_angle;
	double br_proc, br_angle;

	double RollCoeff;

	VESSEL* Booster1;
	VESSEL* Booster2;

	VECTOR3 ControlLevel;

	UINT anim_pitcheng, anim_yaw, anim_shift, anim_pitchglow, anim_yawglow;

	LightEmitter * light;
	LightEmitter * light2;
	LightEmitter * light3;
	//SpotLight *SSME_l;
	LightEmitter * SSME_l;
};

#endif

Edit : the "private" section of Guidance.h is really empty, what you see is the whole file. Should I re-declare all the variables here ? Seems odd.
 
Last edited:
Yeah...visibility of variables... the guidance can't see the variables of your vessel, since it does not know your vessel.

some suggestions for a refactoring:

  1. Move all variables related to the guidance system to the guidance class.
  2. Like jedidia recommended, make Guidance a pointer to an object.
  3. Communicate between the classes only by public functions, not by variables directly.
  4. Follow standard control loop concepts: Navigate, Guide, Control.
  5. For navigation, your guidance class queries the current vehicle state vector from the Sigma rocket vehicle class. Use functions as interface, document the functions properly.
  6. In Guidance, calculate the outputs of the guidance algorithm.
  7. In Control, the Guidance class tells the Sigma vessel class how it should move its engine actuators, etc.

Now something that will maybe only confuse you, so feel free to ignore it and forget that I ever posted it:

Ideally, from a OOP developers viewpoint, define an abstract interface class "IGuidedVessel", that contains no variables etc at all and only abstract virtual functions ("virtual void function() = 0;") that have no implementations yet. inherit SigmaVessel from VESSEL3 and this IGuidedVessel ("class SigmaVessel: public VESSEL3, public IGuidedBessel {..."). Instead of giving your Guidance class a pointer to the actual vessel, give it only a pointer to IGuidedVessel. This means it points to any object of a class that implements IGuidedVessel. This additional step makes testing easier (you can use dummy IGuidedVessel implementations) and permits reuse later (Since you can apply the same guidance class then on other vessels without refactoring for every vessel).
 
One thing is that the variables used in "main2.h" and "main2.cpp" (renamed for simplicity sake) are declared in the "private" section of the class. So I guess they are restricted to the "SigmaStg1" vessel class. Is there any way I can overcome this ?

Sure, you can move them all to public. But that's somewhat amateurish, you want those variables to be private so that they cannot be altered by an accidental call or mistype. Those are the bugs you spend a long time looking for.
Instead, you want to declare public functions tat can access these private variables. That's where all the Get an Set functions come from in the API, for example.

For every variable that needs to be read by another class, you make a public function like
Code:
double GetMass()
{
       return mass;
}

Assuming that mass is the name of your private variable. This way, any other class can call myClass.GetMass() and get the information, without actually getting access to the variables. If a variable needs to be set externally, you write a similar SetMass(double mass) function, that usually comes with some saveguards so that the variable cannot be set to just about anything (for example negative values) which might mess up the whole calculations that follow. This way you can access your private members externally, but do it in a controlled way that helps you reduce bugs.

In "myClass *vessel;", should "myClass" = "Guidance" and *vessel = *SigmaStg1 ?

Ah no, slight misunderstanding. myClass was supposed to be your vessel subclass, so guidance can access the vessels methods. In your case, SigmaStg1 *vessel; Or whatever, the variable name is not that important. Then Guidance can access all public functions of the SigmaStg1 object it was initialised by.

Edit : the "private" section of Guidance.h is really empty, what you see is the whole file. Should I re-declare all the variables here ? Seems odd.

Probably not in the way you think. Redeclaring the variables certainly would make sense, but this will not mean that you have access to the variables of the same name on the other class. They will be different variables.
However, you want to do all the calculations inside the guidance class, and then pass on the result to the vessel, if even tat is necessary. Note that guidance has the capablity of passing the resulting order directly to the vessel (fire thrusters etc), so storing the results of Guidance calculations in you vessel might not be necessary. If the vessel class absolutely needs to know what goes on, pass it the end result, but do not use its variables to store intermiediate steps in the calculation!
 
Last edited:
Another thing you can do is also grouping variables that are meant to be used together into a class of their own... for example StateVector. Of course like said before, access by other classes only by functions, not directly on the variables, unless you have a very good reason why.
 
FYI, for "default" headers (headers from the native C++ libraries, can't remember the technical name for them right now):
#include "math.h"
#include "stdio.h"

Should be:
#include <math>
#include <stdio>

Although I personally still add the .h (i.e. #include <stdio.h>) a lot of times.

Also
Code:
class Guidance
{
public:
	Guidance(void);
	~Guidance(void);
	void GuidanceProgram();
private:

};<- need semicolon here

.... in .cpp file:

void Guidance::GuidanceProgram()
{
     ... blah blah blah...
}<- semicolon NOT needed here
 
Last edited:
So basically, the idea is to do as much stuff as possible in the "subclasses" (like Guidance), then process the results to main2.cpp, that should handle the "concrete" part like actually firing thrusters, playing animations, etc ?

---------- Post added at 01:09 PM ---------- Previous post was at 12:46 PM ----------

Still I don't get why the Orbiter "GetAngularVel(ofs)" function isn't recognized... No obvious reason for that :hmm:
 
So basically, the idea is to do as much stuff as possible in the "subclasses" (like Guidance), then process the results to main2.cpp, that should handle the "concrete" part like actually firing thrusters, playing animations, etc ?

Generally speaking, yeah... Generally speaking.

It's best to break up classes into what seem like logically separated units. For instance in a very simple game similar to orbiter, I might have these classes:
inputObject
planetObject

The inputObject will be responsible for handling input from some device, say a keyboard or a joystick. The planetObject will hold info about a planet, say its mass and position (and even then it might not even have position, some other object, like a physics engine might hold that info).

A good question to ask is "Does this class need to know this stuff?" For instance, if my inputObject was doing operations on a planetObject, the code isn't logically separated well. An input device shouldn't need to know anything about a planet.
 
So basically, the idea is to do as much stuff as possible in the "subclasses" (like Guidance)

Guidance is not a subclass. It's just a class. It doesn't inherit from anywhere, unlike SigmaStg1, which inherits from orbiters VESSEL3 class and is therefore a subclass of VESSEL3 (which in turn inherits from VESSEL2, which inherits from VESSEL).

then process the results to main2.cpp, that should handle the "concrete" part like actually firing thrusters, playing animations, etc ?

Most of the times, even those things can be done by the class. For example, my entire thermodynamics are processed by a class, it calculates and sets temperatures all by itself, it even draws the associated panel elements itself (although one might argue that this isn't well separated, and I would agree. The core structure I inherited from the prior coder is C down to the bone, and I didn't have time to rewrite it. Yet. Ideally, I would put the drawing into yet another class). It asks a lot of information from the my VESSEL class, but it gives almost none in return. Until something isn't the way it should be, then it passes a failure to the vessel, because failure management is centralized, since there are multiple classes all handling their own stuff that can pass a flag if something is wrong. Until then, the central VESSEL class, of which all these other classes are members, has no knowledge whatsoever of what is going on. So, in a nutshell, if you write a class to do a specific job, it should do everything it possibly can do, and only pass information back if that information is needed by another part of the vessel.

In case of a guidance system, I would assume that the class handling it fires all the needed thrusters on vessel externally, without the vessel even realising it's controlled by input from another class instead of the user. Let your left class never know what your right class does ;). It makes code less complicated.

Still I don't get why the Orbiter "GetAngularVel(ofs)" function isn't recognized... No obvious reason for that

Can't tell for sure without code, but I assume It is because you are not calling it from the vessel pointer you passed to Guidance. I.E. if you have a private member
Code:
SigmaStg1 *vessel
in your guidance class, and passed the pointer to the object containing the Guidance object, it has to call
Code:
vessel->GetAngularVel(ofs);
 
Last edited:
Can't tell for sure without code, but I assume It is because you are not calling it from the vessel pointer you passed to Guidance.

Got that working ! I think I begin to get the general idea. :idea:

However, I have at least one "master variable" that is required throughout the code : "MET" (keeps track of the time elapsed, which is essential for a lot of features). What's the simplest way to allow the classes to share it (if we reject the solution of making it public) ?
 
Last edited:
If it is used by several classes, you want to have it in the most central location (presumably your vessel class). I assume that several classes should be able to read it, but none should write to it. That is, it should only get updated at one point in the code. as it is for time keeping, anything else wouldn't make that much sense. So declare it private in your most central class, write a Get-function for it, and you avoid the danger of accidentally modifying it by another class.
 
How should that look like ? :hmm:
Something like this, declared as public:
Code:
ReturnedType TheClass::SomeGetterFunction () {
    return private_variable;
}
 
Thanks, at least I managed to compile the solution and make it run into Orbiter. The autopilot doesn't work, but that was expected. :cool:

So now I have to "trigger" the "GuidanceProgram()" function written in Guidance.cpp from the clbkPostStep(simt...) function in main2.cpp

I tried a couple of things without success (like "Guidance::GuidanceProgram();"), the compiler returns me errors, keeping to say that :
Code:
1>.\main2.cpp(1694) : error C2027: utilisation du type non défini 'Guidance'

Undefined type ? How to fix that ? "Guidance" depends of "main" ; but the contrary should not be true. So I can't use the same tactic than above... :hmm:

or if I simply try "GuidanceProgram();"

Code:
1>.\main2.cpp(1694) : error C3861: 'GuidanceProgram' : identificateur introuvable

Seems the compiler doesn't recognize the function at all there.
 
Last edited:
Code:
1>.\main2.cpp(1694) : error C2027: utilisation du type non défini 'Guidance'

or

Code:
1>.\main2.cpp(1694) : error C3861: 'GuidanceProgram' : identificateur introuvable

And what is on the line 1694 of main2.cpp?
 
is "Guidance::GuidanceProgram();" a static member function?
 
And what is on the line 1694 of main2.cpp?
Only that :

Code:
GuidanceProgram();
I guess I "forgot" something, seems bold to call the function of the other class right away ;)

---------- Post added at 05:06 PM ---------- Previous post was at 05:00 PM ----------

is "Guidance::GuidanceProgram();" a static member function?
Not sure, but I declared it in Guidance.h the "usual way" :

Code:
...
class Guidance{
    friend class SigmaStg1;

public:
    Guidance(void);
    ~Guidance(void);
    [B]void GuidanceProgram();[/B]
...
 
Back
Top