Fanatic23
Fanatic23

Reputation: 3428

Need for out of class definition of static variable?

My question: What exactly is the out of class definition of k doing under the hood to make sure it's address is available?

#include <iostream>
using namespace std;

class A { 
  public: 
  static const float k = 7.7;
};

//const float A::k; --> without this line compiler error

int main()
{
  cout << &A::k;
}

Upvotes: 2

Views: 283

Answers (6)

Naveen
Naveen

Reputation: 73443

The one which is inside the class is the declaration of the variable k. You need to define it in exactly one translation unit in order to link your program correctly. Hence that statement is required.

Upvotes: 1

Billy ONeal
Billy ONeal

Reputation: 106530

Other answers have already given the how to fix it -- I'll go more into the why.

When you do this:

#include <iostream>
using namespace std;

class A { 
  public: 
  static const float k = 7.7;
};

int main()
{
  cout << A::k;
}

The compiler is probably in reality generating this:

#include <iostream>
using namespace std;

class A { 
  public: 
  static const float k = 7.7;
};

int main()
{
  cout << 7.7;
}

which means there will be no link-time dependency between this translation unit and A::f -- the compiled code doesn't reference A::f at all!

However, when you use &A::f, you force the compiler to generate an address for A::f. Therefore that translation unit does have a dependence on A::f. Since you have not defined it, you get a linker error, because the linker cannot find an address for it. For the address to exist, A::f must be defined in one and only one translation unit. To choose the translation unit in which it should reside, you need to define it there.

You also have an invalid code issue with your class above though -- only static const integral members may be initialized with the syntax you've used (putting k = 7.7 in the class body) -- float is not an integral type.

Upvotes: 1

liaK
liaK

Reputation: 11648

If you could define like static const float k = 7.7; as you wish, you will end up in multiple definitions (since static members will be defined only once), wherever you are including it.

To avoid that the definition is made reside separately in a cpp file.

From C++ standard docs sec 9.4.1,

A static data member is not part of the subobjects of a class. There is only one copy of a static data member shared by all the objects of the class.

Also 9.4.2 states that,

The declaration of a static data member in its class definition is not a definition and may be of an incomplete type other than cv-qualified void. The definition for a static data member shall appear in a namespace scope enclosing the member’s class definition.

Hope it helps..

Upvotes: 1

Potatoswatter
Potatoswatter

Reputation: 137780

It sounds like you're wondering why the variable needs to be defined even though you aren't accessing it.

To print its address, it needs to have an address. To have an address, it must exist. To exist, it needs to have a definition and the linker needs to assign it a place in global variable space. So, there really isn't a middle ground.

"Under the hood," the definition tells the linker what the initializer for the global is. (In this case, the initializer is in the class block. But that's nonstandard. The official way is to write const float A::k = 7.7;) Without knowing that, it can't produce the executable file.

Also, unless the compiler performs impossibly detailed analysis, it can't really tell that operator << doesn't somehow pass that pointer to some other function or OS service that will access the value of k.

Upvotes: 1

mukeshkumar
mukeshkumar

Reputation: 2778

A static variable can be deemed as data shared by all the objects of the class and hence only one copy of this variable should be created. With this said, with whom should lie the responsibility of allocationg memory for this member? Obviously it can't be object's responsibility as there could be multiple objects which would raise another challenge as to which object should allocate memory for this member.

So typically compliler expects out of class, explicit definition of this member and hence the line:

const float A::k;

This ensures that the static member variable is accessible to all the objects of the class. The memory for this variable is allocated on globally accessible memory.

Upvotes: 0

Alex Martelli
Alex Martelli

Reputation: 881555

The class "definition" is actually only providing a "declaration" of A::k. Yeah, I know it's confusing, but the idea is to allow the class definition to be in a .h (included from multiple .cpp sources) without creating ambiguities: one, and only one, of those .cpp sources, must provide the actual definition to match A::k's declaration (the latter being part of class A's definition).

Upvotes: 2

Related Questions