How do you make functions visible to all forms in a C++ project?

Hi EE,
I have a Form with many functions.  Some very long.  I would like to create a second Form that can call these functions.  I know one approach would be to declare all these functions (and variables) as extern FunctionName() in Form2 but this is not ideal programming.  I asked a similar question (See ID 26697869) about how to make variables visible in multiple forms and I liked the response--declare the variables as public in the Form1.h file and then include this header file in Form2.  I went down this route for global functions but my functions are too long to be defined in a header file.  What should I do?  Please illustrate your answer with a brief coded example. Thanks,
FA
farcuriAsked:
Who is Participating?
 
HooKooDooKuConnect With a Mentor Commented:
If you leave all the functions inside of Form1, you have to create an instance of Form1 and then call these functions from the Form1 object.

But bartvd is showing you how to simply make your functions global.  By making them global in scope, they are already "public".

Basically, all you do is move all the functions you want to use globally out of Form1 and placement in a stand-alone cpp file... like "Global.cpp".  But you need to do one more step to let all the rest of the code (i.e. the forms) know that these functions exist and what they look like.  To do that, you simply declare the functions in a .h file, and include the .h file in your forms.

The code below shows what sample code would look like for your Form2.cpp, a new Global.h and Global.cpp.  All you have to do is include Global.cpp in your project.

//Form2.cpp
#include "Global.h"    //This is where X2 is declared.

int Form1::Test()
{
    int i = 1;
    int i2 = X2(i);    //X2() is a function that exists in Global.cpp
}


//Global.h
int X2(int);    //This is a DECLARATION of the function



//Global.cpp
#include "Global.h"  //Not required, but helps keep the .cpp and .h in sync
int X2( int i )      //This is the DEFINITION of the X2 function
{
    return i * 2;
}

Open in new window

0
 
bartvdConnect With a Mentor Commented:
You could declare the function in Form1.h and implement it in Form1.cpp

in header file:
void MyFunction(void);

in cpp file:
void MyFunction(void)
{
//your code
}
0
 
farcuriAuthor Commented:
Hi bartvd.  Please clarify.  Are you saying to declare it in Form1.h as a regular function or as a public member function of Class Form1 (As recommended in ID 26697869)?
Also to do it as you suggested do I simply include this Form1.h header file in the Form2.cpp and any other forms that I wish to call MyFunction?
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
farcuriAuthor Commented:
Hi HooKooDooku,
I seem to understand the approach that takes my functions out of Form1 and makes them global in Global.cpp.  I'm going to try it now. But Line 4 is a bit unclear.  Could you explain it?  Is it required?
Also, I am also interested in understanding the other approach--leaving the functions in Form1 and creating an instance of Form1 and calling these from Form1 object.  If you don't mind could you demonstrate this in a similar example?
Thanks,
FA
0
 
HooKooDooKuCommented:
Lines 4 through 8 are just sample code I expect to see in class Form2 (oh, now I see, I have a typo and used Form1 when I ment Form2... it was supposed to be an example of Form2 code calling the sample global function.

As for the other sample, if you wanted to leave all the functions in a Form1 but still be global-lke functions, the code would look something like this (as you can see, lots of extra overhead dealing with code sitting in a class when you just need global defined functions).
//Form2.cpp
#include "Form1.h"    //This is where X2 is declared.

int Form2::Test()  //Notice this is Form2 (TWO) calling global functions
{
    int i = 1;
    Form1 F;
    int i2 = F.X2(i);    //X2() is a function that exists in Form1.cpp
}


//Form1.h
class Form1
{
public:
  int X2(int);    //This is a DECLARATION of the function
}


//Form1.cpp
#include "Form1.h" 
int Form1::X2( int i )      //This is the DEFINITION of the X2 function
{
    return i * 2;
}

Open in new window

0
 
farcuriAuthor Commented:
Hi HooKooDooKu,
I reproduced my own example using the technique you outlined in ID 35743661 where functions are left in Form1 but can be called by Form2.  I had a bit of a struggle to code your line 4.  In fact I dropped using a Test() function altogether.  I attach my code.  Please take a look.  Is it correct?
Any quick tips on how to redo line 4?
How about a general overview regarding using the two approaches to my original question?  Q1. When would it be best to do it with all the global functions in a separate file Globals.cpp?
Q2. When would it be best to leave the functions in Form1 and in Form2 create an instance of Form1 and then call the functions from the Form1 object?
Thanks,
Fabio
unit1.cpp:
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "UnitForm2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::btnClearLabel6Click(TObject *Sender)
{
Form1->Label6->Caption="\0";
}
//---------------------------------------------------------------------------

void __fastcall TForm1::btnSumClick(TObject *Sender)
{
int a,b,Sum;
a=atoi(Edit1->Text.c_str());
b=atoi(Edit2->Text.c_str());
Sum=summer(a,b);
Form1->Label6->Caption=Sum;
}
//---------------------------------------------------------------------------
//this is the definition of summer()
int TForm1::summer(int x,int y)
 {
   return(x+y);
 }
//----------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
Form2->Show();
}

Open in new window

0
 
farcuriAuthor Commented:
And here are the rest of my files:
And you should see that in UnitForm2.cpp I got it to work by declaring:
TForm1 *F;
and then in line 67
 Sum=F->summer(i,j);

 
//Unit1.h
#ifndef Unit1H
#define Unit1H
//-----------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
        TLabel *Label1;
        TLabel *Label2;
        TLabel *Label3;
        TLabel *Label4;
        TLabel *Label5;
        TButton *btnClearLabel6;
        TLabel *Label6;
        TEdit *Edit1;
        TEdit *Edit2;
        TLabel *Label7;
        TButton *btnSum;
        TButton *Button3;
        void __fastcall btnClearLabel6Click(TObject *Sender);
        void __fastcall btnSumClick(TObject *Sender);
        void __fastcall Button3Click(TObject *Sender);
private:	// User declarations
public:		// User declarations
        //declare a function that will be visible globally
        int summer(int x,int y);
        __fastcall TForm1(TComponent* Owner);
};
//-----------------------------------------------------------------extern PACKAGE TForm1 *Form1;
//-----------------------------------------------------------------
#endif
-------------------------------------------------------------------

//UnitForm2.cpp:
#include <vcl.h>
#pragma hdrstop

#include "UnitForm2.h"
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
TForm1 *F;
//void example();
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
        : TForm(Owner)
{
}
//--------------------------------------------------------------------------
void __fastcall TForm2::btnClearLabel1Click(TObject *Sender)
{
Form2->Label1->Caption="\0";
}
//---------------------------------------------------------------------------
void __fastcall TForm2::btnSumClick(TObject *Sender)
{
  int i,j, Sum;
  i=atoi(Form2->Edit1->Text.c_str());
  j=atoi(Form2->Edit2->Text.c_str());
  Sum=F->summer(i,j);
  Form2->Label1->Caption=Sum;        
}

Open in new window

0
 
HooKooDooKuCommented:
The only reason I can think to ever leave global style library functions inside of a Form or Class is because the functions are related to a set of data... but then that's what a class is... data with a set of functions to manipulate the data.

If the functions can stand on their own, then there is no reason I can see to place them inside a class or form.  Especially since it actually takes more overhead to call class functions compared to global library functions.

See, when you call a class member function, in addition to the parameters you pass to the function, the compiler also passes a hidden 'this' pointer, so that the function knows which instance of a class to operate on.  Now in your example of creating a variable of type Form1 pointer, you are avoiding the need to create an instance of a Form1 object before you call  the function TForm1::summer(int x,int y).  But what is happening "under the hood" is that an extra 'this' pointer is getting passed to the summer() function.  In your case, the pointer either has a value of NULL, or some random position in memory if you never initialize the Form1 pointer.  (In either case, if you attempt to access the 'this' pointer within the Form1 functions, you will generate an exception).

So if you truely have a generic function that doesn't rely on any data other than what you pass to it, your code will be cleaner and execute faster if you simply place the functions in global space.  If you should run into problems where the name you want to give to your function conflicts with other global names (the one danger of using global functions), you can always use a namespace and define your library functions inside the name space.

//Global.h
namespace MyUniqueName
{
  int summer(int,int)
}

//Global.cpp
#include "global.h"
namespace MyUniqueName
{
  int summer(int x, int y)
  {
    return x+y
  }
}

//Form2.cpp
using MyUniqueName

void __fastcall TForm2::btnSumClick(TObject *Sender)
{
  int i,j, Sum;
  i=atoi(Form2->Edit1->Text.c_str());
  j=atoi(Form2->Edit2->Text.c_str());
  Sum=summer(i,j);    
  //Sum=MyUniqueName::summer(i,j);     //Alternate way of accessing summer if 'using' statement not used
  Form2->Label1->Caption=Sum;        
}
 
0
 
farcuriAuthor Commented:
HI All at EE,
I am also  having trouble with the variables I put in the Global.h header file.  When I put variables in there (for example int num) and then I include this header file in more than one form I have a linker warning that the variable is declared in more than one file.
Any suggestions?
0
 
farcuriAuthor Commented:
I got it!  I solved the issue with the linker complaining about Global.h variable declarations by declaring them as extern  there and only declaring them once in some other file.
Now I have my real Globals.cpp and Globals.h in my program and it's working very nicely.
I will split the points.
Thanks both bardvd and hookoodooku!
Fabio
0
All Courses

From novice to tech pro — start learning today.