4

This code compiles and works the way I want it, but why?

#include <iostream>

class Test {
private:
  static bool _inited;
  static bool _init() {
    std::cout << "init!" << std::endl;
    return true;
  }
};

bool Test::_inited = Test::_init();

int main(int argc, char** argv) {
}

And if I make what I think is a unrelated change:

bool _inited = Test::_init();

it no longer compiles, giving me the expected error about trying to call a private method.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
MK.
  • 33,605
  • 18
  • 74
  • 111
  • 12
    Because `Test::_inited` is part of the class `Test` (it's the definition of the static data member `Test::_inited`) – milleniumbug Jan 24 '17 at 19:05
  • 2
    `bool _inited = Test::_init();` it's not unrelated. You are simply defining the member outside of the class, not trying to give the value of the member to something else. – George Jan 24 '17 at 19:05
  • Perhaps it would help to explain why you don't expect it to work with the first version. – Matt Jan 24 '17 at 19:10
  • Yeah, thanks. It wasn't obvious (and still seems very unintuitive) that the fact that lhs of assignment is a field, brings the whole statement to be part of the class definition. – MK. Jan 24 '17 at 19:13
  • And if it wouldn't allow this, how else would you define static class members non-inline? :)\ – SergeyA Jan 24 '17 at 19:14
  • @SergeyA I dunno.. I'd have to initialize private static members in the class? Little details like this are super confusing when switching from Java. – MK. Jan 24 '17 at 19:20
  • Also note that you only need to say `bool Test::_inited = _init();` the initializer is looked up in class scope. – Vaughn Cato Jan 25 '17 at 03:41

3 Answers3

4

This code compiles and works the way I want it, but why?

Because where you are using it you are operating at class scope, as part of the class.

It would be the same if you were to write:

static void Test::foo() {
    Test::_init(); // or just _init();
}

Here, the function foo is obviously a part of the class, so you can access every member of Test (be it private or public) in it.

You can even remove the Test::, it is redundant because the compiler will already be looking in the scope of Test for _init(), when _inited is initialized (because it's part of Test).

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
1

I think the following sums it up pretty good. Taken form http://www.cplusplus.com/doc/tutorial/classes/

The scope operator (::) specifies the class to which the member being declared belongs, granting exactly the same scope properties as if this function definition was directly included within the class definition.

I think the same is applicable to everything within the Class, including the static field.

Alex
  • 779
  • 7
  • 15
1

The answer is simple. When you write

bool Test::_inited = Test::_init();

it means that the private static variable of class Test has a value equal to the value that _init() function returns. It is completely valid as you are not trying to access a private function from outside its scope. The Class_Name:: prefix puts them inside the class. They are just not in the class declaration. So in a way its like putting that whole statement inside the class.

Now when you write-

bool _inited = Test::_init();

the variable _inited is different from that of class Test. So it's taking its value from a private data method of a class which is forbidden unless a getter function is used for the assignment.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
Rohan Bhatia
  • 1,870
  • 2
  • 15
  • 31