Why must static data member initialization be outside the class?
class X
{
public:
int normalValue = 5; //NSDMI
static int i;
};
int X::i = 0;
Why is the static data member (here "i") only a declaration, not a definition?
It's important to distinguish the initializer which says what its initial value is, and the definition. This modified code is valid, with the initializer in the class definition:
class X
{
public:
int normalValue = 5;
static const int i = 0; // declaration, with initializer
};
const int X::i; // definition
i.e. What must be outside the class is a definition, not the initialization.
That's because a variable must have an address in memory (unless it's only used in limited situations, such as in compile-time constant expressions.)
A non-static member variable exists inside the object it is a member of, so its address depends on the address of the object that contains it. Every time you create a new X you also create a new X::normalValue variable. The non-static data member's lifetime begins with the class' constructor. NSDMI syntax doesn't have anything to do with the variable's address in memory, it just allows you to provide an initial value in one place, instead of repeating it in every constructor with an explicit constructor initializer list.
On the other hand, a static member variable is not contained within an instance of the class, it exists independently of any single instance and exists from the start of the program, at a fixed address. In order for a static member variable (or any other global object) to get a unique address the linker must see exactly one definition of the static variable, in exactly one object file, and assign it an address.
Because a static variable needs exactly one definition in exactly one object file, it doesn't make sense to allow that definition to be provided in the class, since class definitions typically exist in header files and are included in multiple object files. So although you can provide an initializer in the class, you still need to define the static data member somewhere.
You can also look at it like declaring an extern variable:
namespace X {
extern int i;
}
This declares the variable, but there must be a definition somewhere in the program:
int X::i = 0;
You need to supply a separate definition for a static data member (if its odr-used, as defined in C++11) simply because that definition shall reside somewhere - in one and only one translation unit. Static class data members are basically global objects (global variables) declared in class scope. The compiler wants you to choose a specific translation unit that will hold the actual "body" of each global object. It is you who has to decide which translation unit to place the actual object to.
"static" class member is like a globally allocated variable (it is not related to the single class instance), so it must reside in some object file (and to be declared in the ".cpp" file) as a symbol just like any global variable.
Simple class member (non-static) resides in the memory block allocated for the class instance.
The simple reason is because classes are usually declared in header files, which often are included in multiple cpp files. Static data members have external linkage and must be declared in exactly one translation unit which makes them unfit for being defined inside a class.
As juanchopanza points out the following is allowed:
struct A
{
const static int i = 1;
};
However, this is only a declaration not a definition. You still need to define it if you are going to use i's address somewhere.
For example:
f(int);
g(int&);
X<A::i> x; // Okay without definition for template arguments
char a[A::i]; // Okay without definition, just using value as constant expression
&A::i; // Need a definition because I'm taking the address
f(A::i); // Okay without definition for pass by value
g(A::i); // Need a definition with pass by reference
Bear in mind that is is possible to initialize the static data member at the point of declaration if it is of const integral type of const enumeration type:
From the C++03 standard, §9.4.2
If a static data member is of const integral or const enumeration type, its declaration in the class
definition can specify a constant-initializer which shall be an integral constant expression (5.19)
struct Foo {
static const int j = 42; // OK
};
When the compiler generate binary code from a unit (extreme simplification: a cpp file and all its included headers) it will emit a symbol for the static variable and eventually initialization code for that variable.
It is okay for a static variable symbol to be declared in multiple units, but it is not okay for it to be initialized multiple times.
So you must make sure that the initialization code is only emitted for a single unit.
This mean that the static variable must be defined in exactly one unit.
Static Data Member
#include<iostream.h>
#include<conio.h>
class static_var
{
static int count; //static member of class
public :
void incr_staticvar()
{
count++;
}
void outputc()
{
cout<<"Value of Static variable Count :- "<<count<<endl;
}
};
int static_var::count;
void main()
{
clrscr();
static_var obj1,obj2,obj3,obj4;
obj1.incr_staticvar();
obj2.incr_staticvar();
obj3.incr_staticvar();
obj4.incr_staticvar();
cout<<"\nAfter Increment of static variable by Four Different objects is :-\n";
obj1.outputc ( );
obj2.outputc ( );
obj3.outputc ( );
obj4.outputc ( );
getch();
}
Related
I'm new to C++, and I just can't understand that why I can't assign a value to a non-const static member inside a class (like we do in java static int x = 12; ) even thought I can
declare a non-const static member (static int x;)
declare a static const member (static const x;)
assign a static const member (static const int x = 12;)
note: my class and my main() function are in the same file
In general
A static variable inside a class, just like everything else, is just a declaration by default. C++ then requires you to provide a single definition per entity that requires one, that's the One Definition Rule. The definition is where the initializer (which is not an assignment, but a construction) goes, since there should be only one as well. It is typically placed in a .cpp file so that it can't be accidentally duplicated by #includes.
The constant case
When a static member is a constant integer or enumeration, and is initialized with a compile-time expression, the initializer is allowed to be placed on the declaration, and the definition skipped. This is a result of a combination of old rules and isn't really interesting today IMO.
Proper inline initialization
Since C++17 introduced inline variables, you can use them as static members. The rules are roughly the same as inline functions, and are pretty sensible: you can provide multiple definition of an inline entity, you are responsible for ensuring that they are all strictly identical, and the implementation is responsible for collapsing them into a single definition with its initializer. Thus, what you're looking for is written:
struct Foo {
static inline int bar = 42;
// ^^^^^^
};
You have to initialise the static member outside the class definition like in this example:
class Box {
public:
static int x;
};
// Initialize static member of class Box outside the class definition
int Box::x = 12;
int main(void) {
...
}
Why must static data member initialization be outside the class?
class X
{
public:
int normalValue = 5; //NSDMI
static int i;
};
int X::i = 0;
Why is the static data member (here "i") only a declaration, not a definition?
It's important to distinguish the initializer which says what its initial value is, and the definition. This modified code is valid, with the initializer in the class definition:
class X
{
public:
int normalValue = 5;
static const int i = 0; // declaration, with initializer
};
const int X::i; // definition
i.e. What must be outside the class is a definition, not the initialization.
That's because a variable must have an address in memory (unless it's only used in limited situations, such as in compile-time constant expressions.)
A non-static member variable exists inside the object it is a member of, so its address depends on the address of the object that contains it. Every time you create a new X you also create a new X::normalValue variable. The non-static data member's lifetime begins with the class' constructor. NSDMI syntax doesn't have anything to do with the variable's address in memory, it just allows you to provide an initial value in one place, instead of repeating it in every constructor with an explicit constructor initializer list.
On the other hand, a static member variable is not contained within an instance of the class, it exists independently of any single instance and exists from the start of the program, at a fixed address. In order for a static member variable (or any other global object) to get a unique address the linker must see exactly one definition of the static variable, in exactly one object file, and assign it an address.
Because a static variable needs exactly one definition in exactly one object file, it doesn't make sense to allow that definition to be provided in the class, since class definitions typically exist in header files and are included in multiple object files. So although you can provide an initializer in the class, you still need to define the static data member somewhere.
You can also look at it like declaring an extern variable:
namespace X {
extern int i;
}
This declares the variable, but there must be a definition somewhere in the program:
int X::i = 0;
You need to supply a separate definition for a static data member (if its odr-used, as defined in C++11) simply because that definition shall reside somewhere - in one and only one translation unit. Static class data members are basically global objects (global variables) declared in class scope. The compiler wants you to choose a specific translation unit that will hold the actual "body" of each global object. It is you who has to decide which translation unit to place the actual object to.
"static" class member is like a globally allocated variable (it is not related to the single class instance), so it must reside in some object file (and to be declared in the ".cpp" file) as a symbol just like any global variable.
Simple class member (non-static) resides in the memory block allocated for the class instance.
The simple reason is because classes are usually declared in header files, which often are included in multiple cpp files. Static data members have external linkage and must be declared in exactly one translation unit which makes them unfit for being defined inside a class.
As juanchopanza points out the following is allowed:
struct A
{
const static int i = 1;
};
However, this is only a declaration not a definition. You still need to define it if you are going to use i's address somewhere.
For example:
f(int);
g(int&);
X<A::i> x; // Okay without definition for template arguments
char a[A::i]; // Okay without definition, just using value as constant expression
&A::i; // Need a definition because I'm taking the address
f(A::i); // Okay without definition for pass by value
g(A::i); // Need a definition with pass by reference
Bear in mind that is is possible to initialize the static data member at the point of declaration if it is of const integral type of const enumeration type:
From the C++03 standard, §9.4.2
If a static data member is of const integral or const enumeration type, its declaration in the class
definition can specify a constant-initializer which shall be an integral constant expression (5.19)
struct Foo {
static const int j = 42; // OK
};
When the compiler generate binary code from a unit (extreme simplification: a cpp file and all its included headers) it will emit a symbol for the static variable and eventually initialization code for that variable.
It is okay for a static variable symbol to be declared in multiple units, but it is not okay for it to be initialized multiple times.
So you must make sure that the initialization code is only emitted for a single unit.
This mean that the static variable must be defined in exactly one unit.
Static Data Member
#include<iostream.h>
#include<conio.h>
class static_var
{
static int count; //static member of class
public :
void incr_staticvar()
{
count++;
}
void outputc()
{
cout<<"Value of Static variable Count :- "<<count<<endl;
}
};
int static_var::count;
void main()
{
clrscr();
static_var obj1,obj2,obj3,obj4;
obj1.incr_staticvar();
obj2.incr_staticvar();
obj3.incr_staticvar();
obj4.incr_staticvar();
cout<<"\nAfter Increment of static variable by Four Different objects is :-\n";
obj1.outputc ( );
obj2.outputc ( );
obj3.outputc ( );
obj4.outputc ( );
getch();
}
A .cpp file has a bunch of class definitions . One class has a private static member as follows:
class SomeClass:public SomeParentClass
{
private:
static int count;
};
and right after the class is defined, the count attribute to initialized to zero as follows:
int SomeClass::count = 0;
Coming from the Java/C# world I am having trouble understanding at which point is count initialized to zero? Is it when the SomeClass is instantiated? Also, the class definition has the count type to be int, why does the SomeClass::count has to have an int in front of it?
And my last question is, since the count attribute is private shouldn't its visibility be restricted when it is initialized outside the class definition?
Thanks
Static members of the class are initialized in arbitrary order upon your program's start-up
The static int count; in the class is a declaration of your static variable, while int SomeClass::count = 0; is its definition. All definitions in C++ require to specify a type.
The fact that the definition of the count appears to have occurred in the file scope, the actual scope of the SomeClass::count remains private, as declared.
Is it when the SomeClass is instantiated?
No, you can access it via SomeClass::count (assuming the function has rights to SomeClass's private members) before any instantiations. It's fully usable before you start making objects.
Why does the SomeClass::count has to have an int in front of it?
Well, because it's an int. Think of when you make function prototypes and definitions:
int func (int);
int func (int i) {return 1;} //you still need the int and (int i) here
func {return 1;} //NOT VALID - this is what count would be without int
Since the count attribute is private shouldn't its visibility be
restricted when it is initialized outside the class definition?
Static variable definition is an exception to access specifiers when defined in the normal manner, according to this answer.
The class static variable will behave as if it is initialized to 0 when the program starts. It is independent of class instantiation.
The C++ language requires a type before an identifier in a declaration.
The C++ syntax to initialize a class static variable makes it look like a global, but access to the variable is enforced during compilation.
Why must static data member initialization be outside the class?
class X
{
public:
int normalValue = 5; //NSDMI
static int i;
};
int X::i = 0;
Why is the static data member (here "i") only a declaration, not a definition?
It's important to distinguish the initializer which says what its initial value is, and the definition. This modified code is valid, with the initializer in the class definition:
class X
{
public:
int normalValue = 5;
static const int i = 0; // declaration, with initializer
};
const int X::i; // definition
i.e. What must be outside the class is a definition, not the initialization.
That's because a variable must have an address in memory (unless it's only used in limited situations, such as in compile-time constant expressions.)
A non-static member variable exists inside the object it is a member of, so its address depends on the address of the object that contains it. Every time you create a new X you also create a new X::normalValue variable. The non-static data member's lifetime begins with the class' constructor. NSDMI syntax doesn't have anything to do with the variable's address in memory, it just allows you to provide an initial value in one place, instead of repeating it in every constructor with an explicit constructor initializer list.
On the other hand, a static member variable is not contained within an instance of the class, it exists independently of any single instance and exists from the start of the program, at a fixed address. In order for a static member variable (or any other global object) to get a unique address the linker must see exactly one definition of the static variable, in exactly one object file, and assign it an address.
Because a static variable needs exactly one definition in exactly one object file, it doesn't make sense to allow that definition to be provided in the class, since class definitions typically exist in header files and are included in multiple object files. So although you can provide an initializer in the class, you still need to define the static data member somewhere.
You can also look at it like declaring an extern variable:
namespace X {
extern int i;
}
This declares the variable, but there must be a definition somewhere in the program:
int X::i = 0;
You need to supply a separate definition for a static data member (if its odr-used, as defined in C++11) simply because that definition shall reside somewhere - in one and only one translation unit. Static class data members are basically global objects (global variables) declared in class scope. The compiler wants you to choose a specific translation unit that will hold the actual "body" of each global object. It is you who has to decide which translation unit to place the actual object to.
"static" class member is like a globally allocated variable (it is not related to the single class instance), so it must reside in some object file (and to be declared in the ".cpp" file) as a symbol just like any global variable.
Simple class member (non-static) resides in the memory block allocated for the class instance.
The simple reason is because classes are usually declared in header files, which often are included in multiple cpp files. Static data members have external linkage and must be declared in exactly one translation unit which makes them unfit for being defined inside a class.
As juanchopanza points out the following is allowed:
struct A
{
const static int i = 1;
};
However, this is only a declaration not a definition. You still need to define it if you are going to use i's address somewhere.
For example:
f(int);
g(int&);
X<A::i> x; // Okay without definition for template arguments
char a[A::i]; // Okay without definition, just using value as constant expression
&A::i; // Need a definition because I'm taking the address
f(A::i); // Okay without definition for pass by value
g(A::i); // Need a definition with pass by reference
Bear in mind that is is possible to initialize the static data member at the point of declaration if it is of const integral type of const enumeration type:
From the C++03 standard, §9.4.2
If a static data member is of const integral or const enumeration type, its declaration in the class
definition can specify a constant-initializer which shall be an integral constant expression (5.19)
struct Foo {
static const int j = 42; // OK
};
When the compiler generate binary code from a unit (extreme simplification: a cpp file and all its included headers) it will emit a symbol for the static variable and eventually initialization code for that variable.
It is okay for a static variable symbol to be declared in multiple units, but it is not okay for it to be initialized multiple times.
So you must make sure that the initialization code is only emitted for a single unit.
This mean that the static variable must be defined in exactly one unit.
Static Data Member
#include<iostream.h>
#include<conio.h>
class static_var
{
static int count; //static member of class
public :
void incr_staticvar()
{
count++;
}
void outputc()
{
cout<<"Value of Static variable Count :- "<<count<<endl;
}
};
int static_var::count;
void main()
{
clrscr();
static_var obj1,obj2,obj3,obj4;
obj1.incr_staticvar();
obj2.incr_staticvar();
obj3.incr_staticvar();
obj4.incr_staticvar();
cout<<"\nAfter Increment of static variable by Four Different objects is :-\n";
obj1.outputc ( );
obj2.outputc ( );
obj3.outputc ( );
obj4.outputc ( );
getch();
}
This is an expansion of the scope of a previous question of mine.
What exactly is "static", how is it used, and what is the purpose of using "static" when dealing with C++?
Thanks.
It means that the variable is local to a translation unit (simply put, to a single source file), and cannot be accessed from outside it. This use of static is in fact deprecated in the current C++ Standard - instead you are supposed to use anonymous namespaces:
static int x = 0;
should be:
namespace {
int x = 0;
}
The keyword static has different meanings in C++, depending on the context.
When declaring a free function or a global variable it means that the function is not to be available outside of this single translation unit:
// test.cpp
static int a = 1;
static void foo() {}
If the result of compiling that translation unit is linked with a different translation unit containing symbols a and foo it will not break the One Definition Rule, as in this particular translation unit a and foo are private symbols. This use has been obsoleted by unnamed namespaces.
// test2.cpp
namespace {
static int a = 1;
static void foo() {}
}
When declaring a local variable within a function it means that the lifetime of the variable will extend from the first call to the function to the end of the program, and not only for the duration of the call:
int foo() {
static int counter = 0;
return ++counter;
}
int main() {
for ( int i = 0; i < 10; ++i ) {
std::cout << foo() << std::endl;
}
}
In the previous code, counter is initialized once when foo is called for the first time, but the variable will outlive the function and keep the value across different function calls. The previous code will print "1 2 3 4... 10". If the variable was not declared static then the output would be "1 1 1... 1".
Within a class scope, static means that the member is a member of the class, and not of a particular instance. This use is equivalent to the use in your other question: usage of that particular member is not bound to any specific object.
struct test {
int x;
static int y;
};
int test::y; // need to define it in one translation unit
int main() {
// test::x = 5; // !error cannot access a non-static member variable
// without an instance
test::y = 5; // ok
test t, other;
t.x = 10; // ok
t.y = 15; // ok, the standard allows calling a static member through
// an instance, but this is the same as test::y
}
In this case, the member x is a non-static member attribute, and as such there is a different x for each instance of the class. In the sample program t.x and other.x refer to different integers. On the other hand y is static and thus there is a single instance of test::y in the program. Even if the standard allows to call t.y and other.y both uses refer to the same variable. The same goes with member methods. If they are static they are class-level methods and can be called without an instance, while if they are non-static they are applied to a concrete instance and the a.b or a->b syntax must be used.
This use of static is similar to the use of the same keyword in Java, while the other two are not present in that language. There is one use of the keyword in Java that is not present in C++, and that is the use of static class initializers (a block of code at class level surrounded by static { ... }). In Java that block of code will be executed when the class is loaded and only once. Initialization of static member variables in C++ must be done in the initializer of the variable definition.
This stuff seems to be fairly well covered here.
But to paraphrase, there are 2 uses in C
Prevent the use of a global variable outside the scope of the file that defines it.
Allow local variables within a function to persist accross invocations of the function, as in
int getNextId()
{
static int id = 0;
return id++;
}
C++ inherits both of these, and adds two uses of its own.
static member variables: Variables that are "shared" accross all instances of a class, and can also be accesses without reference to an instance of the class. Shared seems like the wrong word, but in essence I beleive that the result is that any reference to a static member variable references the same memory location.
static methods: Methods that can be called without reference to a specific instance of the class that defines it.
Static basically means that a variable is tied to the lifetime of the program and not of any given function or class instance. When should you use it? Don't. What is the purpose? Debugging data, mostly.
Generally, in C++, if you find yourself using static data, you've done it wrong. There are times when it's appropriate, but they're very rare.
When static is used in a class in C++, it means more or less the same thing that it does in Java. For variables it means that one one instance of the variable exists for all classes and for functions, it means that the function does not implicitly access the this pointer at all.
In C and C++ when static is used for a global variable or function, then it means that the variable may only be referenced in the current C or C++ file. In other words, the compiler must not generate any relocation symbols for the variable or function.
When static is used next to a variable in a local function, it means that the variable does not go out of scope but will retain its value from function-call to function-call. The variable become effectively a global variable that can only be accessed from the given function.
Static class members are data and functions that are associated with the class itself, rather than with the objects of the class.
In the following example, class Fred has a static data member x_ and an instance data member y_. There is only one copy of Fred::x_ regardless of how many Fred objects are created (including no Fred objects), but there is one y_ per Fred object. Thus x_ is said to be associated with the class and y_ is said to be associated with an individual object of the class. Similarly class Fred has a static member function f() and an instance member function g().
class Fred {
public:
static void f() throw(); <-- 1
void g() throw(); <-- 2
protected:
static int x_; <-- 3
int y_; <-- 4
};
(1) Member function associated with the class
(2) Member function associated with an individual object of the class
(3) Data member associated with the class
(4) Data member associated with an individual object of the class
Usage:
When you want to keep tract of the number of instances of a class created you use static variable. For example in a 'Car' class each Car instance may have a unique serial number(_y in this case) and the company may want to keep track of the number of cars produced(_x in this case).