Link to home
Start Free TrialLog in
Avatar of forums_mp
forums_mp

asked on

object visibility / access issue


Consider:

// test.h
#ifndef TEST_H
#define TEST_H

struct test_struct;

class test {
  test_struct msg;            // static instance msg
public:
  test();
  void get_data();
  void updateData(test_struct& test_);
};

#endif

// test.cpp
# include "test.h"
# include "test_struct.h"

test m_test;           // global instance

test::test() {}
void test::get_data() {}
void test::updateData(test_struct& test_) {}

// test_struct.h
#ifndef TEST_STRUCT_H
#define TEST_STRUCT_H

# include "test.h"

extern test m_test;
struct test_struct
{
  test_struct() {}
  void test_me() {
    m_test.updateData(*this);
  }
};

#endif


// main.cpp
# include <iostream>
# include <string>
# include "test.h"

using namespace std;
extern test m_test;
int main()
{
  m_test.get_data();
}


Within test.h, there's a forward declaration of test_struct.    A msg object of type test_struct is desired and instantiated privately within 'test'.   Trouble is:  There lies the problem.   It is desired to have a global instance of m_test.  That said, to alleaviate the issue with the msg object, I suspect one solution is to have the move/define the msg object globally within 'test.cpp'.  So now:

// test.cpp
# include "test.h"
# include "test_struct.h"

test m_test;                  // global instance
test_struct msg;            // static instance msg

test::test() {}
void test::get_data() {}
void test::updateData(test_struct& test_) {}

Alternatives are of course welcome.  Note:  m_test needs to be accessible within test_struct and the msg object should not be a pointer.  If there's a way to eliminate the global m_test by passing things around then by all means demonstrate.


Note: The purpose of a singleton is to make sure, that a specific object exists only once (or a specific number of times) in your whole system, hence I dont desire a singleton here.
Avatar of Axter
Axter
Flag of United States of America image

What exactly is your question?

Notice that there is not question in your posted question.
>>>> Within test.h, there's a forward declaration of test_struct

A forward declaration isn't sufficient if you have a member object (the compiler needs the size of the member). Forward declarations can be used for pointers and references only.

You need to include test_struct.h within test.h.

You can get rid of the global test instance by defining a static member in some other class. However if you need a singleton of that class as well you are lost ...

Another way is to define a static pointer or static reference in test class

class test
{
private:
   
public:
   static test& theTest;
    ...
};

Then in test.cpp you need

#include "test.h"
test& test::theTest = *(new test);

You would access it from other cpp by

     test::theTest.doWhatYouAreSupposedToDo();

Regards, Alex
You can't have an instance until you've defined the class... so you can't forward declare test_struct yet have a (non-pointer) version in the test class.

You'd have to use a pointer..


.. Your requirement and question aren't too clear...
Avatar of forums_mp
forums_mp

ASKER


Alex,

|  You need to include test_struct.h within test.h.

And rightly so, since 'test_struct' is undefined.  So now I  include  "test_struct.h" and here's what I get:


main.cpp
c:\sw_dev\global_test\test_struct.h(13) : error C2146: syntax error : missing ';' before identifier 'm_test'
c:\sw_dev\global_test\test_struct.h(13) :  error C2501: 'm_test' : missing storage-class or type specifiers
At issue:
The line, 'extern test m_test;' in test_struct.h

c:\sw_dev\global_test\main.cpp(11) : error C2146: syntax error : missing ';' before identifier 'm_test'
c:\sw_dev\global_test\main.cpp(11) : error C2501: 'm_test' : missing storage-class or type specifiers
c:\sw_dev\global_test\main.cpp(11) : error C2086: 'int m_test' : redefinition
c:\sw_dev\global_test\main.cpp(15) : error C2228: left of '.get_data' must have class/struct/union type

See below for the lines (11) and (15)


# include <iostream>
# include <string>
# include "test.h"




using namespace std;

extern test m_test;         // (11)

int main()
{
  m_test.get_data();       //(15)
}
SOLUTION
Avatar of Axter
Axter
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>>>> c:\sw_dev\global_test\test_struct.h(13) : error C2146: syntax error : missing ';' before identifier 'm_test'

Seems as you wanted to have a 'test' member in 'test_struct' and a 'test_struct' member in 'test'.

That isn't possible as both would need the full class definition of the member *before* each class definition. If you have two classes that need each other as members you have to use reference or pointer type, e. g.  Parent* pParent if you have a parent - child relation...

But before you do it that way, you should check if you actually need both relations... In the code above where the only test instance is a globally defined singleton, you wouldn't need a member of type test in any other class. You don't need pointers or references to globally defined singletons.

Regards, Alex





Axter, some general question.

The initilzation of the reference below requires the dynamic allocation.  I'm unsure why?

  test::test():msg(*(new test_struct)){}

Say  I removed 'test.cpp'.  So now all the functionality is IN test.h.  i.e

#ifndef TEST_H
#define TEST_H

# include "test_struct.h"

struct test_struct;

class test {
  test_struct& msg;
public:
  test() : msg(*(new test_struct)){}
  ~test() { delete &msg;}
  void get_data() {}
  void updateData(test_struct& test_) {}
};
#endif

This wont work.  Is it safe to state that the reason is because of the 'circular include - if you will'?  IOW.  With this approach, with test.h I now:
# include "test_struct.h" which includes "test.h"

Bottom line: I'm unsure why you need to move function bodies - so to speak - inside a cpp for this to work.

One other question:  Lets add a new twist to this:

////////////////////////////////////////////////////////////////////////////////////
#ifndef TEST_IMPL_H
#define TEST_IMPL_H
# include "test.h"

class test_impl {
  //test *m_test;
  test m_test;
public:
  test_impl () { //m_test = new test();
  }
  ~test_impl () { //delete m_test;
   }
};

#endif
////////////////////////////////////////////////////////////////////////////////////
// test.h
#ifndef  TEST_H
#define TEST_H

struct test_struct;

class test {
  test_struct& msg;
public:
  test();
  ~test();
  void get_data();
  void updateData(test_struct& test_);
};

#endif
////////////////////////////////////////////////////////////////////////////////////

// test.cpp
# include "test.h"
# include "test_struct.h"

test::test():msg(*(new test_struct)){}
test::~test(){delete &msg;}
void test::get_data() {}
void test::updateData(test_struct& test_) {}
////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////
// test_struct.h
#ifndef TEST_STRUCT_H
#define TEST_STRUCT_H

#include "test.h"

//extern test m_test;
struct test_struct
{
  test_struct() {}
  void test_me() {
    m_test.updateData(*this);
  }
};

#endif

////////////////////////////////////////////////////////////////////////////////////
// main.cpp
# include <iostream>
# include <string>
# include "test_impl.h"

using namespace std;

int main()
{
  test_impl m_test_impl;
  return 0;
}


The test_impl function now owns the m_test object.  test_struct though needs visibility into m_test.  What's the recommendation here?

>>Bottom line: I'm unsure why you need to move function bodies - so to speak - inside a cpp for this to work.

You need it to avoid the circular includes.

>>The test_impl function now owns the m_test object.  test_struct though needs visibility into m_test.  What's the recommendation here?

I'm not sure what is the question.
Are you having problems with this code, if so, please give details.
>>Bottom line: I'm unsure why you need to move function bodies - so to speak - inside a cpp for this to work.

Just remember, that the compiler can not create an instance of an object without knowning the details of the object.
It can reference an object via reference or via pointer, because it doesn't need any details to refer to an object via reference or pointer.
A pointer for a struct or class will always be the same size, and it's just a place holder for the object.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial

Axter,

You missed my question(s) here:  05/31/2005 05:09PM PDT

| I'm not sure what is the question.
| Are you having problems with this code, if so, please give details.  
The previous code is fine.   My post here  05/31/2005 07:10PM PDT was similar to the previous except now the rec object was moved inside an 'test_impl' class.  I just wanted to achieve the same result.   I think I see I solution though based on the response from you and Alex.