16
#include <stdio.h>

class C
{
   public:
          static int i;
          static int j;
};

int i = 10;
int C::i = 20;
int C::j = i + 1;

int main ()
{
    printf("%d", C::j);

    return 0;
}

What is the value of: C::j

I was reading a c++ quiz and came across the following question. I thought that the answer is 11.

int C::j = i + 1;

Since it is accessing the non static i which is 10? So, I thought 11 should be the answer?

I compiled and ran this code through visual studio and it prints 21. Which is confusing to me. Can someone please explain why this is happening? What am I missing?

Mayank Patel
  • 3,868
  • 10
  • 36
  • 59
marsh
  • 2,592
  • 5
  • 29
  • 53
  • One of the reasons I hate C++. In an "ideal world", if you say "i", you get "i". Instead of the stupid language second-guessing and giving you "C::i" instead. I believe the workaround - if you want "10" - is to qualify `int C::j = ::i + 1;`. – paulsm4 Sep 02 '15 at 21:06
  • 1
    Yea, I knew I could use ::i to be explicit but I did not think I needed to. – marsh Sep 02 '15 at 21:08
  • 6
    The language isn't second-guessing anything. This behaviour is the same as the behaviour of defining functions out-of-line. Inside the body of a function of `C` you would not want to type `C::i` every time you meant the member, would you? – Brian Bi Sep 02 '15 at 21:16
  • 1
    @Brian Although, that would simplify things a lot if you always had to write `this->member`. – Barry Sep 02 '15 at 21:30
  • @Brian Coming from a Python background: yes. Yes I would. Except `C` is the name of a class, and what I really want is the name of the instance. So `this->` is...almost what I want, except `->` is a lot more awkward than `.`. – Kyle Strand Sep 03 '15 at 18:16

1 Answers1

24

[basic.lookup.qual]/3

In a declaration in which the declarator-id is a qualified-id, names used before the qualified-id being declared are looked up in the defining namespace scope; names following the qualified-id are looked up in the scope of the member’s class or namespace.

In

int C::j = i + 1;

the declarator-id, i.e., the name of the entity being declared, is C::j, which is a qualified-id. Therefore, the i following it is looked up in the scope of C, and refers to C::i.

Less technically, when you define a static data member, the initializer can be thought of as being in the scope of the class, and will find class members before globals.

This is the same rule that ensures that when a member function is defined out-of-line, names after the name of the function will be looked up in class scope and won't require explicit qualification if they refer to class members. It is more unusual seeing this being applied to definitions of static data members, but it is perfectly consistent.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • 2
    Should probably add why `C::j` necessarily gets initialized after `C::i`, so it's definitely 21 and not 1. – Barry Sep 02 '15 at 21:35