How to make a variable avaliable to multiple .cpp

2019-08-10 12:25发布

问题:

This question has derived from this one.

I have a working program which must be split into multiple parts. In this program is needed to use a variable (now it's a GTK+ one :P) many times in parts of the program that will end up in separated .cpp files.

So, I made a simple example to understand how to make variables avaliable to the program parts. A modified version of the previous code would be:

#include <iostream>

using namespace std;

int entero = 10;

void function()
    {
    cout<<entero<<endl;
    //action1...;
    }

void separated_function()
    {
    cout<<entero<<endl;
    //action2...;
    }

int main( int argc, char *argv[] )
    {
    function();
    separated_function();
    cout<<entero<<endl;
    //something else with the mentioned variables...;
    return 0;
    }

It is needed to split the code correctly, to have function(), another_function() and main() in separated .cpp files,and make entero avaliable to all of them... BUT:

In the previous question @NeilKirk commented:Do not use global variables. Put the required state into a struct or class, and pass it to functions as necessary as a parameter (And I also have found many web pages pointing that is not recommended to use global variables).

And, as far I can understand, in the answer provided by @PaulH., he is describing how to make variables avaliable by making them global. This answer was very useful, it worked fine not only with char arrays, but also with ints, strings and GTK+ variables (or pointers to variables :P).

But since this method is not recommended, I would thank anyone who could show what would be the correct way to split the code passing the variables as a function parameter or some other method more recommended than the - working - global variables one.

I researched about parameters and classes, but I'm a newbie, and I messed the code up with no good result.

Thanks for any help.

回答1:

Defining a class or struct in a header file is the way to go, then include the header file in all source files that needs the classes or structures. You can also place function prototypes or preprocessor macros in header files if they are needed by multiple source files, as well as variable declarations (e.g. extern int some_int_var;) and namespace declarations.

You will not get multiple definition errors from defining the classes, because classes is a concept for the compiler to handle, classes themselves are never passed on for the linker where multiple definition errors occurs.


Lets take a simple example, with one header file and two source files.

First the header file, e.g. myheader.h:

#ifndef MYHEADER_H
#define MYHEADER_H
// The above is called include guards (https://en.wikipedia.org/wiki/Include_guard)
// and are used to protect the header file from being included
// by the same source file twice

// Define a namespace
namespace foo
{
    // Define a class
    class my_class
    {
    public:
        my_class(int val)
            : value_(val)
        {}

        int get_value() const
        {
            return value_;
        }

        void set_value(const int val)
        {
            value_ = val;
        }

    private:
        int value_;
    };

    // Declare a function prototype
    void bar(my_class& v);
}

#endif // MYHEADER_H

The above header file defines a namespace foo and in the namespace a class my_class and a function bar.

(The namespace is strictly not necessary for a simple program like this, but for larger projects it becomes more needed.)

Then the first source file, e.g. main.cpp:

#include <iostream>
#include "myheader.h"  // Include our own header file

int main()
{
    using namespace foo;

    my_class my_object(123);  // Create an instance of the class

    bar(my_object);  // Call the function

    std::cout << "In main(), value is " << my_object.get_value() << '\n';

    // All done
}

And finally the second source file, e.g. bar.cpp:

#include <iostream>
#include "myheader.h"

void foo::bar(foo::my_class& val)
{
    std::cout << "In foo::bar(), value is " << val.get_value() << '\n';
    val.set_value(456);
}

Put all three files in the same project, and build. You should now get an executable program that outputs

In foo::bar(), value is 123
In main(), value is 456


回答2:

You need to give the parameter as a reference if you want the same comportement as a global variable

#include <iostream>

using namespace std;


// renamed the parameter to avoid confusion ('entero' is valid though) 
void function(int &ent)
{
    cout<<ent<<endl;
    ++ent; // modify its value
    //action1...;
}

void separated_function(int &ent)
{
    cout<<ent<<endl;
    ++ent; // modify its value again
    //action2...;
}

int main( int argc, char *argv[] )
{
    int entero = 10; // initializing the variable

    // give the parameter by reference => the functions will be able to modify its value
    function(entero);
    separated_function(entero);

    cout<<entero<<endl;
    //something else with the mentioned variables...;
    return 0;
}

output:

10
11
12


回答3:

I prefer to provide a functional interface to global data.

.h file:

extern int get_entero();
extern void set_entero(int v);

.cpp file:

static int entero = 10;

int get_entero()
{
   return entero;
}

void set_entero(int v)
{
   entero = v;
}

Then, everywhere else, use those functions.

#include "the_h_file"

void function()
{
    cout << get_entero() << endl;
    //action1...;
}

void separated_function()
{
    cout << get_entero() << endl;
    //action2...;
}

int main( int argc, char *argv[] )
{
    function();
    separated_function();
    cout<< get_entero() <<endl;
    //something else with the mentioned variables...;
    return 0;
}


回答4:

If you do not plan to modify the variable, it is generally ok to make it global. However, it is best to declare it with the const keyword to signal the compiler that it should not be modified, like so:

const int ENTERO = 10;

If you are using multiple cpp files, also consider using a header file for your structures and function declarations.

If you are planning on modifying the variable, just pass it around in function parameters.