When a static member variable is declared private in a class, how can it be defined?
Suppose i have the following class declaration
class static_demo
{
private:
static int a;
public:
static int b;
void set(int x, int y)
{
a = x;
b = y;
}
void show()
{
cout << "a = " << a << "\n";
cout << "b = " << b << "\n";
}
};
Then the following statement to define a will result in compilation error.
int static_demo::a;
So is it possible to have a static data member in the private section of class?
Adding full code as per Greg,
#include <iostream>
using namespace std;
class static_demo
{
private:
static int a;
public:
static int b;
void set(int x, int y)
{
a = x;
b = y;
}
};
int static_demo::a;
int static_demo::b;
int main()
{
static_demo::b = 10;
static_demo::a = 20;
return 0;
}
The compilation error is:
static_member_variable.cpp: In function `int main()':
static_member_variable.cpp:20: error: `int static_demo::a' is private
static_member_variable.cpp:26: error: within this context
When a static member variable is declared private in a class, how can it be defined?
In the very same way as you define a public static variable in your source(cpp) file.
int static_demo::a = 1;
Access specifiers will not give you error while defining the member. Access specifiers control the access of the member variables, defining a static variable is an excpetion which is allowed.
Compiles cleanly on Ideone here.
EDIT: To answer your Q after you posted code.
Your problem is not the definition of the static member. The error is because you are trying to access the private static member inside main. You cannot do that.
Private members of a class can only be accessed inside the class member functions, the same rule applies even to static members. To be able to modify/access your static members you will have to add a member function to your class and then modify/access the static member inside it.
in your .cpp:
int static_demo::a(0);
when this causes an error, it is most common that you either encountered a linker error for a multiply defined symbol (e.g. the definition was in the header), or that you may have tried to define it in the wrong scope. that is, if static_demo is in the namespace MON, it would be defined in the .cpp:
#include "static_demo.hpp"
int MON::static_demo::a(0);
for other types, it may simply have been an incorrect constructor.
The problem is not the definition, but the fact that in main() (that's not in the name scope of static_demo, and cannot see a being private), you do an assignment.
The definition of a is what you did at global scope, with int static_demo::a;.
You simply need an initializer, if you want a not to start with an undefined value.
int static_demo::a = 1;
will solve the problem.
From than on, a can be manipulated only by functions in static_demo (of friend of it).
Related
#include <iostream>
class Test {
public:
static int numelem;
Test() {}
~Test() {}
int increment();
};
int Test::numelem = 0;
int Test::increment()
{
return ++Test::numelem;
}
So I want to make a counter for my Stacks data structure.
Whenever I push, it increments and when popped it decrements.
My code works, but int Test::numelem = 0; is a global variable.
I tried using inline but unfortunately I have C++14.
I only put the static int numelem instead of the whole Stack class to focus on one feature.
Is there an alternative way I can put int Test::numelem = 0; inside the class without getting any error?
This is the typical workaround. It's particularly useful for templates.
class Test {
public:
static int& numelem() {
static int val = 0; // or your initializer here
return val;
}
int increment() {
return ++numelem();
}
};
Of course, now you're accessing it with the syntax Test::numelem() instead of just Test::numelem. But something like ++Test::numelem() still works just fine.
but int Test::numelem = 0; is a global variable.
Technically, it is not a global variable but a class static member. Functionally they behave very similarly.
Is there an alternative way I can put int Test::numelem = 0; inside the class without getting any error? unfortunately I have C++14.
With C++14 the out-of-class definition for a nonconst static data member should be in the same namespace scope where the class was defined(global namespace in your example). So there is no way of defining a nonconst static data member inside the class in c++14 as we can't use inline in c++14 and the only way of defining a nonconst static data member is to put a definition at namespace scope.
This can be seen from class.static.data:
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.
But with C++17 we can use inline to define a non-const static data member inside the class.
I wrote the following snippet in the same file where the main function is. However, the Live Semantic Error feature in Visual Studio says that 'a nonstatic member reference must be relative to a specific object'. In my opinion, the x in function m should be the int x defined in the file-scope and it should be accessible in everywhere of this file.
Please point out where I misunderstood. Thank you in advance!
int x = 0;
class Test1{
protected:
char *x;
class Test2{
public:
int m(){
return x++;
}
};
};
What you've created here is a nested class: The name of the nested class exists in the scope of the enclosing class, and name lookup from a member function of a nested class visits the scope of the enclosing class after examining the scope of the nested class.
When you refer to x within Test1::Test2::m() in your example, the compiler is going to go up the scope chain and find the first x to be Test1::x. Because this isn't a static member variable you're getting the error.
If you want to refer to the global x use ::x. I modified your example to demonstrate:
#include <stdio.h>
int x = 0;
class Test1{
public:
char *x;
class Test2{
public:
int m(){
return ::x++;
}
};
};
int main() {
printf("x = %d\n", x);
Test1::Test2 foo;
foo.m();
printf("x = %d\n", x);
return 0;
}
This prints:
x = 0
x = 1
$.02 note on style: If you reserve nested classes for simple data containers that only operate on themselves, as is a common best practice, you won't run into this issue.
#include <iostream>
using namespace std;
class Box
{
public:
static int objectCount;
}
// Initialize static member of class Box
int Box::objectCount = 0;
It seems that you mix up the declaration and the definition of a variable.
The declaration just tells the compiler a name.
So in your case:
class Box
{
public:
static int objectCount;
};
This just tells the compiler that there is a variable with the name objectCount.
But now you still need a definition.
int Box::objectCount = 0;
Simplified the definition is what the linker needs.
So as a simple rule static member variables must be declared in the class and then defined outside of it.
I would like to have a static member variable keep track of the amount of objects that have been made. Like so:
class test{
static int count = 0;
public:
test(){
count++;
}
}
That doesn't work because, according to VC++, a member with an in-class initializer must be constant. So I looked around and apparently you're supposed to do:
test::count = 0;
Which would be great, but I want count to be private.
edit:
Oh boy, I just realized I need to do:
int test::count = 0;
I had seen something just do test::count = 0, so I assumed you wouldn't have to declare type again.
I'd like to know if there's a way to do this inside the class though.
edit2:
What I'm using:
class test{
private:
static int count;
public:
int getCount(){
return count;
}
test(){
count++;
}
}
int test::count=0;
Now it's saying: 'test' followed by 'int' is illegal (did you forget a ';'?)
edit3:
Yup, forgot a semicolon after the class definition. I'm not used to having to do that.
Put
static int count;
In your header in the class definition, and
int test::count = 0;
In the .cpp file. It will still be private (if you leave the declaration in the header in the private section of the class).
The reason you need this is because static int count is a variable declaration, but you need the definition in a single source file so that the linker knows what memory location you're referring to when you use the name test::count.
Initialization of static variable within a function is allowed so a solution can be something like this
class test
{
private:
static int & getCount ()
{
static int theCount = 0;
return theCount;
}
public:
int totalCount ()
{
return getCount ();
}
test()
{
getCount () ++;
}
};
in general using this technique it is possible to work around the C++ limitation regarding static member initialization in the declaration.
static class members must be defined (and potentially initialized) at namespace scope, member access rules do not apply.
Failed to link up following two files, when I remove the "static" keyword, then it is okay. Tested with g++.
Check with readelf for the object file, the static member seems is exported as a global object symbol... I think it should be a local object ...?
static1.cpp
class StaticClass
{
public:
void setMemberA(int m) { a = m; }
int getMemberA() const { return a; }
private:
static int a;
};
int StaticClass::a = 0;
void first()
{
StaticClass statc1;
static1.setMemberA(2);
}
static2.cpp
class StaticClass
{
public:
void setMemberA(int m) { a = m; }
int getMemberA() const { return a; }
private:
static int a;
};
int StaticClass::a = 0;
void second()
{
StaticClass statc1;
static1.setMemberA(2);
}
With error infoļ¼
/tmp/ccIdHsDm.o:(.bss+0x0): multiple
definition of `StaticClass::a'
It seems like you're trying to have local classes in each source file, with the same name. In C++ you can encapsulate local classes in an anonymous namespace:
namespace {
class StaticClass
{
public:
void setMemberA(int m) { a = m; }
int getMemberA() const { return a; }
private:
static int a;
};
int StaticClass::a = 0;
} // close namespace
void first()
{
StaticClass statc1;
static1.setMemberA(2);
}
The following is a definition of the static data member. It has to occur only in one file that's compiled and then linked.
int StaticClass::a = 0;
If you have multiple such definitions, it is as if you had multiple functions called first. They will clash and the linker will complain.
I think you are mistaking static members with static applied to namespace scope variables. At the namespace level, static gives the variable or reference internal linkage. But at the class scope level (when applied to a member), it will become a static member - one that is bound to the class instead of each object separately. That then has nothing to do with the C meaning of "static" anymore.
The statement
int StaticClass::a = 0;
actually allocates storage for the variable, this is why it should be only written once.
As for your remark, you are probably confusing two different uses of the static keyword. In C static used to mean "use internal linkage", this means that the name of a variable or function would not be seen outside the translation unit where it was defined.
In classes, static is used to define class members, that is variables or methods that don't refer to a specific instance of the class. In this case the storage for a static variable must be allocated somewhere (as it is not part of any instance), but only in one place of course.
StaticClass needs a place to store a, a static variable that will be shared by all class instances - there are two lines that do so, one in each file. Removing one will fix the linker error.