0

G'day,

Using C++, I would like to have a global object which contains several public member objects which can be accessed “through” the global object, while at the same time the code in the member objects should be able to call methods in the global object by accessing it as a global object (i.e. without passing a specific reference to the global object into the member objects).

I thought this would be quite straight forward, along the lines of my simplified example code below, but it won’t compile. Within the IDE, while viewing the header files I get “redefinition of GlobalObject / MemberObject” and "unknown type name" warnings (despite the “pragma once” in each header file ?). And when I compile the code the compiler reports “GlobalObject / MemberObject is undefined” errors.

I guess I have some sort of circular reference problem, though to be honest I don’t really understand why, as while the global object contains a reference to the member object(s), the member object(s) don’t contain a reference to the global object because I intend them to access the global object in the same way any other code would access it directly from the main function…? Doesn’t making GlobalObject global by declaring it outside of the main function then referencing it as external in the MemberObject header file do this, or am I mistaken here ?

I know people have strong opinions about the evil of global objects, but I believe there are circumstances where they are appropriate, especially in embedded systems with limited resources and which essentially “start-up” and never “shut-down” (or at least don’t shut-down in a controlled manner - the power just goes off). So I would like to know how what I am trying to do can be made to work, or if it can’t, I would like to understand why not.

I would appreciate any guidance anyone might like to offer, thank you.

GlobalObject.h

#pragma once

#include "MemberObject.h"

class GlobalObject
{
  private:
    int               Data;
    int               Total;

  public:
    GlobalObject();
    MemberObject      MO;
    int               GetData(void);
    void              SetData(int NewData);
    int               GetTotal(void);
    void              SetTotal(int NewTotal);
};

GlobalObject.cpp

#include "GlobalObject.h"

GlobalObject::GlobalObject() : MO()       { Data = 0; Total = 0; }

int  GlobalObject::GetData(void)          { return Data; }
void GlobalObject::SetData(int NewData)   { Data = NewData; }

int  GlobalObject::GetTotal(void)         { return Total; }
void GlobalObject::SetTotal(int NewTotal) { Total = NewTotal; }

MemberObject.h

#pragma once

#include "GlobalObject.h"

extern GlobalObject GO;

class MemberObject
{
  private:
    int               Data;

  public:
    MemberObject();
    int               GetData(void);
    void              SetData(int NewData);
    void              SetGlobalTotal(void);
};

MemberObject.cpp

#include "MemberObject.h"

MemberObject::MemberObject()              { Data = 0; }

int  MemberObject::GetData(void)          { return Data; }
void MemberObject::SetData(int NewData)   { Data = NewData; }

void MemberObject::SetGlobalTotal(void)   { GO.SetTotal(GO.GetData() + Data); }

main.cpp

#include "GlobalObject.h"

GlobalObject GO;

int main(void)
{
  GO.SetData(1000);
  GO.MO.SetData(2000);
  GO.MO.SetGlobalTotal();
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
Martin Irvine
  • 161
  • 1
  • 2
  • 8
  • 1
    Do you know how #include works? You cannot have a loop where two files include each other. (Well, you can, but it won't work how you expect) – user253751 Feb 01 '16 at 02:48

3 Answers3

1

This is something you should try to avoid when designing your classes.

If the global object is a singleton, one option is to have a global reference to that object, then everyone can go in via that reference. (This is somewhat common for things like logging frameworks, resource pools etc.) Trevor Hickey's answer uses this option.

The only other way is to have the sub-object know about the parent explicitly: the MemberObject constructor could accept a reference to a GlobalObject which is its parent. (Don't use a pointer as that will lead to Rule of Three issues)

M.M
  • 138,810
  • 21
  • 208
  • 365
  • I have been fiddling with this problem and have come to accept your are right. I want the parent and its children to be self-contained so I need only instantiate an instance of the parent to use it and its children. So I think your second option is the way to go. (Somehow, I now feel I should have known that before I started on the global parent scheme as I have done it this way before by passing a parent pointer in the child ctors). I now note what you say about passing a reference not a pointer, but what is the 'right way' to get a reference to the parent to pass to the child ctors? – Martin Irvine Feb 01 '16 at 07:48
  • Pass `*this` from parent – M.M Feb 01 '16 at 07:54
  • 1
    Thank you for your advice. This aspect of the project has been completed successfully as per your recommendations. – Martin Irvine Mar 02 '16 at 05:15
0

What seems to be the issue?

struct Member{
  void method(){}
};

struct Global{
  Member member;
};

//global instance
Global global;

int main(){
  global.member.method();
}
Trevor Hickey
  • 36,288
  • 32
  • 162
  • 271
  • Trevor, thanks for your interest. I see you are suggesting structs not classes. I do not know what the significance of this is, but will investigate and test this. But could you briefly explain what you intend the difference to be ? Thank you. – Martin Irvine Feb 01 '16 at 02:36
  • `struct` is `public` by default, `class` is `private`. http://stackoverflow.com/questions/54585/when-should-you-use-a-class-vs-a-struct-in-c – Tas Feb 01 '16 at 02:40
  • Hi again. I don't think the public vs private difference is relevant to my problem ? I have now read a bit and experimented with this, but I don't think it changes anything. – Martin Irvine Feb 01 '16 at 03:03
0

Using C++, I would like to have a global object which contains several public member objects which can be accessed “through” the global object, while at the same time the code in the member objects should be able to call methods in the global object by accessing it as a global object (i.e. without passing a specific reference to the global object into the member objects).

While you can do this, it points to a possible flaw in your design. Ideally, the member objects of the global object shouldn't rely on the global object to do their job. I would advise taking a step back and rethinking your design.

The simplest analogy I can give is that the nodes of a linked list don't rely on the linked list to be well defined and do their job. The link list, on the other hand, relies on the details of the node to do its job.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Hello R Sahu, thanks for your interest. I believe I understand the point you are making, though in this case I think my approach is reasonable. The code I provided above is only a simple demo of the problem I am having. In fact I am writing a kind of device driver for some hardware, and the hardware is complex enough that I want to implement some sections of the driver as "sub-components", especially where there are multiple instances of them. But in some cases when changing settings in a "sub-component" I need the sub-component code update a setting in the top-level driver object... – Martin Irvine Feb 01 '16 at 02:54
  • @MartinIrvine, in that case, the [signals and slots mechanism](http://stackoverflow.com/questions/312895/what-are-signals-and-slots) is worth looking into. – R Sahu Feb 01 '16 at 02:59