0

I have a class called class object which have variable called density (_OMEGA is related to density : density = _OMEGA*x). I also have configuration file(a txt file) where I say _OMEGA = 1.4. Then I read that _OMEGA and other configuration variable from the txt file into a container in class config which I will be using in my project during runtime.

Now I make lots of this class object, since I make many of them I don't want to pass _OMEGA to each of these object during creation since I don't want to store this _OMEGA in each of these class object. (I use _OMEGA just to vary the density variable in class object)

I know static variable are idle for these case but I am not sure how to go ahead and use it.

  • I know MACRO are idle for this but I don't want to use them in this particular case.

What I have done so far is :

In main.cpp after reading the config file I do

object::_OMEGA = config.get_val("OMEGA");

I get undefined reference to object::_OMEGA

I think why I get this error since I did not do the object::_OMEGA = config.get_val("OMEGA"); in the cpp file. But if I do this in cpp file then I have to pass the config reference to all object class, which seems counter productive.

To avoid this error I did :

double object::_OMEGA = 0; 

and in .h file of object I declared a variable static double _OMEGA

I now compiles but now sure if this is the right way to do thing.

  • Why don't you use a singleton here? – qwerty_so Dec 8 '16 at 20:44
  • @ThomasKilian But I will be creating multiple instance of object. Where did you mean to use singleton? – solti Dec 8 '16 at 20:49
  • I mean to put that single variable in a singleton so you have only one instance. – qwerty_so Dec 8 '16 at 20:50
  • @ThomasKilian so make double _OMEGA to static double _OMEGA ? – solti Dec 8 '16 at 20:56
  • Can you create an instance of this object with the Omega value and then only create the other instances that are a clone of this object? – JeffO Dec 8 '16 at 22:32
1

since I make many of them I don't want to pass _OMEGA to each of these object during creation

You don't really have a choice. The other alternatives suck much more, it's just over a longer period of time.

  • How about doing object::_OMEGA = config.get_val("OMEGA"); outside of class? – solti Dec 8 '16 at 19:48
  • That sucks considerably more, just over a longer period. – DeadMG Dec 9 '16 at 22:39
0

As the value of Omega is to be a fixed value shared across all the objects, your gut feeling of creating it as a static makes sense. That way you won't burden each object with this variable. Also the same can be scaled to cater to a host of other config data if required.

You could restrict the population of Omega to only once by either using a macro (like in the code below) or an static bool attribute that can be initialised to false and later set to true in static function CObject::SetOmega().

Irrespective of how many times you call the CObject::SetOmega(), it will only set the value once.

As Config class was not under discussion, I've placed some functional definition into the .h file for brevity of answer here.

CObject.h .

#ifndef COBJECT_H
#define COBJECT_H
#define UNPOPULATED_OMEGA -1
class CObject
{
    static float s_mOmega;
    float mDensity;
public:
    CObject(int dnstFactor);
    static void SetOmega(float omega);
    static float GetOmega();
    float GetDensity()const;
};
#endif //COBJECT_H

. .

CObject.cpp .

#include "CObject.h"                              

float CObject::s_mOmega = UNPOPULATED_OMEGA;

CObject::CObject(int dnstFactor)
{
    mDensity = s_mOmega * dnstFactor;
}

void CObject::SetOmega(float omega)
{
    if(s_mOmega == UNPOPULATED_OMEGA)
        s_mOmega = omega;
}

float CObject::GetOmega()
{
    return s_mOmega;
}

float CObject::GetDensity()const
{
    return mDensity;
}

. .

Config.h .

#ifndef CCONFIG_H
#define CCONFIG_H
#include <iostream>
#include <string>

class Config
{
public:
    Config(const char* configFileName)
    {
        std::cout << "Loading from file " << configFileName << std::endl;
    }

    float get_val(const std::string& key)
    {
        if (!key.compare("OMEGA"))
            return 1.4f;
    }
};
#endif //CCONFIG_H

. .

main.cpp .

#include <iostream>
#include "Config.h"
#include "CObject.h"

using namespace std;

int main()
{
    Config config("config.txt");
    CObject::SetOmega(config.get_val("OMEGA"));

    CObject obj1(10);
    cout << "Obj1 --> " << obj1.GetDensity() << endl;

    CObject obj2(10);
    cout << "Obj2 --> " << obj2.GetDensity() << endl;

    CObject::SetOmega(100);

    CObject obj3(10);
    cout << "Obj3 --> " << obj3.GetDensity() << endl;

    CObject::SetOmega(200);

    CObject obj4(10);
    cout << "Obj4 --> " << obj4.GetDensity() << endl;

    return 0;
}
0

So you need this value when instantiating your classes.

Here's the simplest thing you could do. Pass your config from higher up in your dependency graph and then use it when creating your classes. (I'll use pseudo code, my point is fairly language agnostic):

class Foo {
    Foo(config Config){
       _config = config; // I'm assuming your have an object which encapsulates your config?
    }

    DoSomething() {
        var myobject = new MyObject(_config.omega);
        ....
    }
};

Alternatively, a pattern you can use to allow the Foo class to create a MyObject without knowing about it's (potentially many) dependancies is the factory pattern:

class Foo {
    Foo(myObjectFactory MyObjectFactory){
       _myObjectFactory = myObjectFactory; 
    }

    DoSomething() {
        var myobject = myObjectFactory.Create();
        ....
    }
};

class MyObjectFactory {
    MyObjectFactory(config Config) {
        _config = config;
    }

    Create() {
        return new MyObject(_config.omega);
    }
}

Using a factory is probably overkill in this case, since MyObject only has one dependancy, but can be useful for classes with more dependencies, which then have their own dependencies etc etc.

So I'd recommend starting with wrapping your config in a Config class, and passing that to your Foo-like objects, as in my first example. This config class shouldn't be a singleton, but it's sensible to only create it once (very high up the dependency tree, or in your DI container if you have one), and either make its values lazy or initialized in its constructor.

Don't use God objects, statics and globals. These make code hard to reason with, hard to separate and impossible to make threadsafe.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.