how to correct it so I can display the static int by
cout<<A::a<<endl;
like in an example below?
#include <iostream>
using namespace std;
class A{
public:
static int a = 0;
};
int main()
{
cout << A::a << endl;
return 0;
}
Inside the class definition, the static members are only declared and not defined. By default, only definitions have initialization, with the exception that for static constants of integral types the declaration can have the initialization.
The problem in your program is that the static member is used (std::cout << A::a is odr-use for non-const static member attributes), but you have no definition. You need to define the variable in a single translation unit in your program by adding:
int A::a = value;
(Note that because the static member is not const, you cannot provide an initializer inside the class definition, so you need to remove the = 0 from the declaration in class definition. Also note that you can skip the = value in the initialization if value == 0, as static initialization will set A::a to 0 before any other initialization)
Either:
class A{
public:
static const int a = 0;
};
(const integral types can be initialized inside the class definition)
or
class A{
public:
static int a;
};
int A::a = 0;
Related
So inside header files I can do
namespace X {
doThis();
}
and in the implementation file I can do
namespace X {
doThis() { .... }
}
But if I have a class
class X {
public:
doThis();
};
Is it possible for me to do something like this in the implementation file
class X {
doThis() { .... }
}
instead of X::doThis() { .... }?
There's the "Java hack"¹, where you "inherit" from the class to get its members into your namespace:
class MyUserType : /*protected|private*/ X {
void foo() {
doThis(); // works
}
}
Of course this only works of
the class doesn't define additional (non-static) features that interfere when inherited
your calling code is in a class that can inherit from the type
the derived class is not a template because 2-phase lookup makes things weird again (though you can use using declarations to mitigate them, on a name-by-name basis)
Re: static data members/out of class definition
In the comments you seem to have a problem with brevity of code mostly. Look into
Disclaimer: following examples largely copied from cppreference
inline variables (c++17), which is about namespace level static variables, which also applies to class members:
constexpr/const static member initialization right in the declaration.
If a static data member of integral or enumeration type is declared const (and not volatile), it can be initialized with an initializer in which every expression is a constant expression, right inside the class definition:
struct X
{
const static int n = 1;
const static int m{2}; // since C++11
const static int k;
};
const int X::k = 3;
constexpr members are even required to have the initializer in the declaration:
struct X {
constexpr static int arr[] = { 1, 2, 3 }; // OK
constexpr static std::complex<double> n = {1,2}; // OK
constexpr static int k; // Error: constexpr static requires an initializer
};
Note that in some circumstances you may still need out-of-class definitions, but without the initializer:
If a const non-inline (since C++17) static data member or a constexpr static data member (since C++11)(until C++17²) is odr-used, a definition at namespace scope is still required, but it cannot have an initializer. A definition may be provided even though redundant (since C++17).
struct X {
static const int n = 1;
static constexpr int m = 4;
};
const int *p = &X::n, *q = &X::m; // X::n and X::m are odr-used
const int X::n; // … so a definition is necessary
constexpr int X::m; // … (except for X::m in C++17)
¹ for the longest time Java didn't have enumerations, so you'd define static constants in a base class an "inherit" from it to get the constants.
² If a static data member is declared constexpr, it is implicitly inline and does not need to be redeclared at namespace scope. This redeclaration without an initializer (formerly required as shown above) is still permitted, but is deprecated.
the following code in my opinion should output sum sizeof(int) + sizeof(float) + sizeof(std::string), but the storage value is always zero. Why?
struct Base {
static int IncrementID(int x) {
static int id = 0;
storage += x;
return id++;
}
static int storage;
};
int Base::storage = 0;
template<typename T>
struct Object : public Base {
static const int id;
};
template<typename T>
const int Object<T>::id(Base::IncrementID(sizeof(T)));
int main() {
Object<int> a;
Object<float> b;
Object<std::string> c;
std::cout << Base::storage;
}
You don't use those static id data members in any way that can cause their implicit instantiation. It means they don't have to be instantiated (nor their initialization has to happen). To quote the C++ standard:
[temp.inst]
3 Unless a member of a class template or a member template has
been explicitly instantiated or explicitly specialized, the
specialization of the member is implicitly instantiated when the
specialization is referenced in a context that requires the member
definition to exist; in particular, the initialization (and any
associated side effects) of a static data member does not occur unless
the static data member is itself used in a way that requires the
definition of the static data member to exist.
Doing something as simple as adding a user defined constructor like
Object() {
int i = id;
(void)i;
}
Can be enough to odr-use them, and as such force their instantiation by creating objects as you do.
Is it possible to use a variable in an inner class declared in Outer class .
I would like to achieve like the following. Is it possible.
I am getting the following error.
prog.cc: In constructor 'Outer::Inner::Inner()': prog.cc:12:25: error: invalid use of non-static data member 'Outer::i'
Inner( ) { i = 5; };
#include <iostream>
using namespace std;
class Outer {
public:
int i;
class Inner; // forward declaration of Outer::Inner
friend class Inner;
class Inner {
Inner() {
i = 5;
};
};
};
int main() {
return 0;
}
Unlike Java, C++ "inner classes" have no connection to the outer class that created them. You will have to pass in a pointer or reference to the outer class.
From the working draft of the standard available online:
9.7 Nested class declarations [class.nest]
A class can be declared within another class. A class declared within another is called a nested class. The name of a nested class is local to its enclosing class. The nested class is in the scope of its enclosing class.
Example:
int x;
int y;
struct enclose {
int x;
static int s;
struct inner {
void f(int i) {
int a = sizeof(x); // OK: operand of sizeof is an unevaluated operand
x = i; // error: assign to enclose::x
s = i; // OK: assign to enclose::s
::x = i; // OK: assign to global x
y = i; // OK: assign to global y
}
void g(enclose* p, int i) {
p->x = i; // OK: assign to enclose::x
}
};
};
inner* p = 0; // error: inner not in scope
As you can see from the example provided in the document, the only way for a nested class to access a non-static member of the enclosing class is through a pointer to the enclosing class.
That is what happens in void g(enclose* p, int i)
I'm reading Scott Meyers' C++ and come across this example:
class GamePlayer{
private:
static const int NumTurns = 5;
int scores[NumTurns];
// ...
};
What you see above is a declaration for NumTurns, not a definition.
Why not a definition? It looks like we initialize the static data member with 5.
I just don't understand what it means to declare but not define a variable with the value 5. We can take the address of the variable fine.
class A
{
public:
void foo(){ const int * p = &a; }
private:
static const int a = 1;
};
int main ()
{
A a;
a.foo();
}
DEMO
Because it isn't a definition. Static data members must be defined outside the class definition.
[class.static.data] / 2
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.
As for taking the address of your static member without actually defining it, it will compile, but it shouldn't link.
you need to put a definition of NumTurns in source file, like
const int GamePlayer::NumTurns;
Is it possible to initialize a static const value outside of the constructor? Can it be initialized at the same place where member declarations are found?
class A {
private:
static const int a = 4;
/*...*/
};
YES you can but only for int types.
If you want your static member to be any other type, you'll have to define it somewhere in a cpp file.
class A{
private:
static const int a = 4; // valid
static const std::string t ; // can't be initialized here
...
...
};
// in a cpp file where the static variable will exist
const std::string A::t = "this way it works";
Also, note that this rule have been removed in C++11, now (with a compiler providing the feature) you can initialize what you want directly in the class member declaration.
Static data members (C++ only)
The declaration of a static data member in the member list of a class is not a definition. You must define the static member outside of the class declaration, in namespace scope. For example:
class X
{
public:
static int i;
};
int X::i = 0; // definition outside class declaration
Once you define a static data member, it exists even though no objects of the static data member's class exist. In the above example, no objects of class X exist even though the static data member X::i has been defined.
Static data members of a class in namespace scope have external linkage. The initializer for a static data member is in the scope of the class declaring the member.
A static data member can be of any type except for void or void qualified with const or volatile. You cannot declare a static data member as mutable.
You can only have one definition of a static member in a program. Unnamed classes, classes contained within unnamed classes, and local classes cannot have static data members.
Static data members and their initializers can access other static private and protected members of their class. The following example shows how you can initialize static members using other static members, even though these members are private:
class C {
static int i;
static int j;
static int k;
static int l;
static int m;
static int n;
static int p;
static int q;
static int r;
static int s;
static int f() { return 0; }
int a;
public:
C() { a = 0; }
};
C c;
int C::i = C::f(); // initialize with static member function
int C::j = C::i; // initialize with another static data member
int C::k = c.f(); // initialize with member function from an object
int C::l = c.j; // initialize with data member from an object
int C::s = c.a; // initialize with nonstatic data member
int C::r = 1; // initialize with a constant value
class Y : private C {} y;
int C::m = Y::f();
int C::n = Y::r;
int C::p = y.r; // error
int C::q = y.f(); // error
The initializations of C::p and C::q cause errors because y is an object of a class that is derived privately from C, and its members are not accessible to members of C.
If a static data member is of const integral or const enumeration type, you may specify a constant initializer in the static data member's declaration. This constant initializer must be an integral constant expression. Note that the constant initializer is not a definition. You still need to define the static member in an enclosing namespace. The following example demonstrates this:
#include <iostream>
using namespace std;
struct X {
static const int a = 76;
};
const int X::a;
int main() {
cout << X::a << endl;
}
The tokens = 76 at the end of the declaration of static data member a is a constant initializer.
Just for the sake of completeness, I am adding about the static template member variables.
template<class T> struct X{
static T x;
};
template<class T> T X<T>::x = T();
int main(){
X<int> x;
}
You cannot initialize static members within constructors. Integral types you can initialize inline at their declaration. Other static members must be defined (in a .cpp) file:
// .h
class A{
private:
static const int a = 4;
static const foo bar;
...
...
};
// .cpp
const foo A::bar = ...;