Go Down

Topic: Problem with accessing a variable (Read 198 times) previous topic - next topic

RogerInHawaii

Feb 23, 2021, 05:43 am Last Edit: Feb 23, 2021, 05:44 am by RogerInHawaii
This one has me stumped.

I've got a class defined within a class. It seems to accept that just fine. But there's a variable that I'm referencing from within a function that's causing a compile error, namely an undefined reference.

Here's the pertinent code:

 
Code: [Select]
class GPS
{
  public:

  class Messages
  {
    public:

    // Here's the variable, within the Messages class, that it's having trouble with.
    static unsigned int MessageNumber;

    static void Initialize()
    {
      // When I reference that MessageNumber variable from within this function I get:
      // undefined reference to `GPS::Messages::MessageNumber'
      MessageNumber = 1;
    }



Both the variable and the function are defined as static and public, so I don't see why it's saying that the reference is undefined.

Anyone have any ideas?

UKHeliBob

Please post a complete sketch that illustrates the problem
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

6v6gt

see the comments in code based on: https://www.learncpp.com/cpp-tutorial/static-member-variables/


Code: [Select]

class GPS
{
  public:

    class Messages
    {
      public:

        // Here's the variable, within the Messages class, that it's having trouble with.
        static unsigned int MessageNumber;   // declaration only

        static void Initialize()
        {
          // When I reference that MessageNumber variable from within this function I get:
          // undefined reference to `GPS::Messages::MessageNumber'
          MessageNumber = 1;
        }
    };
};


unsigned int GPS::Messages::MessageNumber{ 1 } ;  // definition and initialisation

void setup() {
  Serial.begin(115200) ;
  Serial.println( GPS::Messages::MessageNumber ) ;
}

void loop() {
}

RogerInHawaii

6v6gt, Thank you,
Putting that 

unsigned int GPS::Messages::MessageNumber{ 1 } ;
completely outside of the class definition itself solves the problem. 

But reading through the documentation you referenced, it notes that it's also possible to do it INSIDE the class, like this, using the bracket type initialization:

Code: [Select]
  class Messages
  {
    public:
   
    static unsigned int MessageNumber{ 1 };


However, when I do that the Arduino compiler generates an error:

ISO C++ forbids in-class initialization of non-const static member 'GPS::Messages::MessageNumber'
So it seems that the Arduino compiler accepts SOME official ways to do it but not others.

I'm a retired software engineer with decades of writing C++ programs and have never encountered a problem with initializing static variables directly within a class. If memory serves correctly (it's been a while) you could do it with a simple assignment:
static unsigned int MessageNumber = 1 ;
I'm assuming that there's been some major (philosophical?) changes in the definition of C++ since I retired. But, dang, declaring things OUTSIDE of the class definition itself, ... that just seem mighty weird. A major idea regarding classes is that everything is defined right there INSIDE the class. So having to put some code OUTSIDE the class in order to get a variable described INSIDE the class to work properly  just seems ... WEIRD!  :smiley-confuse:

Heck, you don't have to do anything special outside the class for static FUNCTIONS defined inside the class. [ sigh ]

RogerInHawaii

Please post a complete sketch that illustrates the problem
No, I will NOT post a complete sketch. I posted the RELEVANT section of code that isolates and clearly defines the issue that I am encountering.

As you can clearly see from the OTHER response to my posting, what I posted was indeed perfectly sufficient for someone to understand the issue and provide a solution to it.

I've posted other issues that I've encountered in the past, always limiting the code to RELEVANT code, and invariably someone responds with your type of response, namely an assertion to post a "complete sketch".

IT'S NOT NECESSARY!!!

In fact, it usually makes it more difficult to understand what the problem is since the complete sketch will contain lots and lots of code having nothing at all to do with the issue at hand. I am always THANKFUL when someone else takes the time to simplify and isolate the relevant code for the problem that they're encountering, rather than presenting reams of code having nothing to do with the issue that they're encountering.

6v6gt

You should, at least, take the trouble to post a compilable block of code, if you are asking people to help you, so that they can quickly test it and duplicate the error condition.

UKHeliBob

Quote
I will NOT post a complete sketch. I posted the RELEVANT section of code that isolates and clearly defines the issue that I am encountering.
Experience shows that when people post code snippets the problem is very often caused by something in the code that they did not post, hence my request, but feel free to post incomplete code in the future if that is what you want to do.
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

RogerInHawaii

You should, at least, take the trouble to post a compilable block of code, if you are asking people to help you, so that they can quickly test it and duplicate the error condition.
As you can see, from the OTHER (incredibly helpful) reply that I received, presenting a compilable block of code was not at all necessary to fully address the issue. That other respondent was able to look at what I wrote and say, "Oh, I see what the problem is, here's the solution...". No compiling necessary.

My approach is that I TAKE THE TROUBLE to clearly and concisely describe the issue and limit any code to what is pertinent to that issue.  Too many people post way too much code and woefully inadequate explanations, making it quite difficult for any reader to understand what the actual problem is.

Now, there are certainly times when someone has an issue that's of the form: "I've written a program, it doesn't do what I expect it to do, and I have no clue what might be wrong with my code." In such cases it may well be necessary to post the entire program.

But just responding to ANY posting that doesn't have complete, compilable code with an assertion that it NEEDS to have such code in order for anyone to respond, is not helpful. And not true.

TheMemberFormerlyKnownAsAWOL

#8
Feb 23, 2021, 04:49 pm Last Edit: Feb 23, 2021, 07:10 pm by TheMemberFormerlyKnownAsAWOL
Code: [Select]
class Messages
  {
    public:
   
    static unsigned int MessageNumber{ 1 };
};
...is indeed sufficient to return the given error message from the GNU compiler. (You can even omit the "public", with the same outcome)


@OP - good luck with the attitude - hope it works for you.
Please don't PM technical questions - post them on the forum, then everyone benefits/suffers equally

jimLee

Why define a class in a class? I've never seen this. What does doing this buy you?

-jim lee
PNW Ardiuno & Maker club
1012 9Th Street, Anacortes, WA 98221 (Around the back of building)
GITHUB -> https://github.com/leftCoast

TheMemberFormerlyKnownAsAWOL

Why define a class in a class? I've never seen this. What does doing this buy you?
Double encapsulation?
Please don't PM technical questions - post them on the forum, then everyone benefits/suffers equally

jimLee

PNW Ardiuno & Maker club
1012 9Th Street, Anacortes, WA 98221 (Around the back of building)
GITHUB -> https://github.com/leftCoast

TheMemberFormerlyKnownAsAWOL

Makes it "safer"?

-jim lee
Always limit scope to the bare minimum.
Please don't PM technical questions - post them on the forum, then everyone benefits/suffers equally

RogerInHawaii

Why define a class in a class? I've never seen this. What does doing this buy you?

-jim lee
It makes sense when the included class is ONLY used within the encompassing class, only has relevance to the encompassing class.  In my particular case I've defined a class for handling a GPS device. That class will handle GPS messages, so I've included a Messages class within the GPS class. Within that Messages class I'll have a generic Message class plus separate classes derived from that generic Message class for each of the large number of messages. A perfectly reasonable hierarchy of classes. It keeps things organized.

Coding Badly

...is indeed sufficient to return the given error message from...
...all standards compliant C++ compilers.

Ooh.  Visual Studio let's you easily select which standard.  That's cool.

Off to play with Rust...


Go Up