I want to write a little Singleton class that looks like:
#include <vector>
class Interpreter {
private:
static Interpreter* interInstance;
Interpreter() {}
public:
static Interpreter* getInstance();
~Interpreter() {}
};
Interpreter* Interpreter::interInstance = 0;
Interpreter* Interpreter::getInstance(){
if (!interInstance)
interInstance = new Interpreter();
return interInstance;
}
But this will produce this exception:
multiple definition of `Interpreter::getInstance()
This error can be corrected by wrapping the class and the function in one namespace.
But I don't really understand why I need a namespace.
There is one declaration of getInstance() and one implementation, no?
Move the definition outside the header, in an implementation file, for both the member initialization and the method:
Interpreter.h
class Interpreter {
private:
static Interpreter* interInstance;
Interpreter() {}
public:
static Interpreter* getInstance();
~Interpreter() {}
};
Interpreter.cpp
#include "Interpreter.h"
Interpreter* Interpreter::interInstance = 0;
Interpreter* Interpreter::getInstance(){
if (!interInstance)
interInstance = new Interpreter();
return interInstance;
}
Inside a class or struct definition, static doesn't give symbols internal linkage as it does outside, so you're breaking the one definition rule.
If multiple translation units include a header that contains non-inline methods or define the same symbol, you'll run into multiple definition.
Related
I create a basic IBasic interface with a static field
class IBasic
{
public:
IBasic();
virtual ~IBasic();
static std::vector< std::vector<char> > Field;
};
from which the Inherit class is inherited:
class Inherit : public IBasic
{
public:
Inherit(int);
~Inherit();
void Foo();
};
The Inherit class makes some manipulations with Field static member in constructor/or member function.
In order to create an instance of the Inherit class, we need to explicitly declare a static field in the main.cpp before the main function:
#include "Basic.h"
#include "Inherit.h"
std::vector< std::vector<char> > IBasic::Field;
int main()
{
Inherit(10);
return 0;
}
The questions are:
In what namespace does the static method actually exists (global?)? Because I know that static field/function is not a class member in fact.
Is there another way to declare this static method, for example, in a
class file, inside a main function, or through creation unnamed namespace? Is it only one right variant?
How is right? What should be considered first of all?
A static member of a class is a member of its class (that's a tautology) and its class namespace (a class is a namespace). It is not a nember of any other namespace.
A non-const static data member of a class must be defined exactly once in a program, outside of any class, in the same namespace its class is defined in (a global namespace in your case). A header file is inappropriate place for such declaration. It is normally placed in an implementation .cpp file that goes together with the header file.
Having said that, an interface should not have any static data members, much less public ones. It is most likely a grave design error.
In what namespace does the static method actually exists (global?)? Because I know that static field/function is not a class member in fact.
It is declared in scope of the class. In fact the static variable is a class member, your assumption is wrong.
Is there another way to declare this static method, for example, in a class file, inside a main function, or through creation unnamed namespace? Is it only one right variant?
The usual way is to define it in the translation unit that contains the function definitions for the class.
How is right? What should be considered first of all?
There's no right or wrong way, but as mentioned definition in the same translation unit as the class function definitions is the usual way.
Here's an example usage of a static member without any inheritance.
SomeClass.h
#ifndef SOME_CLASS_H
#define SOME_CLASS_H
class SomeClass {
private:
int x;
public:
static SomeClass* const get(); // Needed For Using class to get this pointer
SomeClass();
int getX() const { return x; }
void setX( int val ) { x = val; }
};
#endif // SOME_CLASS_H
SomeClass.cpp
#include "SomeClass.h"
static SomeClass* s_pSomeClass = nullptr;
SomeClass::SomeClass() {
s_pSomeClass = this;
}
SomeClass* const SomeClass::get() {
if ( nullptr == s_pSomeClass ) {
// throw exception
}
return s_pSomeClass;
}
Another class using above class as a static member
OtherClass.h
#ifndef OTHER_CLASS_H
#define OTHER_CLASS_H
class SomeClass; // Forward Declaration
class OtherClass {
private:
static SomeClass* pSomeClass; // The Static Member to this class
int y;
public:
OtherClass();
int getY() const { return y; }
void setY( int val ) { y = val; }
void useSomeClassToSetY();
};
#endif // OTHER_CLASS_H
OtherClass.cpp
#include "OtherClass.h"
#include "SomeClass.h"
SomeClass* OtherClass::pSomeClass = nullptr;
OtherClass::OtherClass() {
if ( nullptr == pSomeClass ) {
pSomeClass = SomeClass::get();
}
}
void OtherClass::useSomeClassToSetY() {
// First Set X To Some Value:
pSomeClass->setX( 10 ); // Use of Static Member
y = pSomeClass->getX(); // Use of Static Member
}
Static members still belong to the class, but they have static storage.
/*
* CDummy.h
*/
#ifndef CDUMMY_H_
#define CDUMMY_H_
class CDummy {
public:
CDummy();
virtual ~CDummy();
};
#endif /* CDUMMY_H_ */
I've read that one should not declare class variables in header files. ist this right?
So I declare it in the cpp file below:
/*
* CDummy.cpp
*/
#include "CDummy.h"
static int counter = 0; //so here is my static counter. is this now private or public? how can i make it public, i cannot introduce a public block here.
CDummy::CDummy() {
counter++;
}
CDummy::~CDummy() {
counter--;
}
using this code i cannot access the classvariable from my main program....
thx
A "class variable" needs to belong to a class. So it has to be declared in the class definition. If the class definition is in a header file, then it follows that the class variable declaration must also be in a header file.
The class variable's definition should go in an implementation file, typically the one in which the class' members are defined. Here's a simplified example:
Foo.h
struct Foo
{
void foo() const;
static int FOO; // declaration
};
Foo.cpp
void Foo::foo() {}
int Foo::FOO = 42; // definition
What you have here:
static int counter = 0;
is a static variable that is not a static member of any class. It is only non-member static variable, static to the compilation unit of CDummy.cpp.
static int counter = 0; //so here is my static counter. is this now private or public? how can i make it public, i cannot introduce a public block here.
From the code I see counter is just a global static variables as it is not declated anywhere in your CDummy
Static variables should be public so that you could initialize them outside the class declaration. Your code should look like this to have it public:
class CDummy {
public:
static int count;
CDummy();
virtual ~CDummy();
};
// inside CDummy.cpp
int CDummy::count = 0;
Here you can read more about how to use static variables in class declaration.
I am currently doing a checker for the top level domains of email addresses. In order to check, I am comparing it to a list that is a text file. I want to import the list into a static map container. However, when I try to instantiate it, it says that it cannot be defined in the current scope. Why is that?
This is some my header file:
class TldPart {
public:
static void LoadTlds();
private:
static map<string,bool> Tld;
}
Here is the implementation in the cpp:
void TldPart::LoadTlds()
{
map<string,bool> Tld;
...
}
It is telling me that ValidTld cannot be defined in the LoadTlds function.
Static members of a class exist outside of an object. You should define and initialize static member outside of the class.
Here we define and initialize a static class member:
header-file:
#pragma once
#include <map>
#include <string>
class TldPart {
public:
static void LoadTlds();
private:
static std::map<std::string, bool> tld;
};
your cpp-file:
#include "external.h"
std::map<std::string,bool> TldPart::tld;
void TldPart::LoadTlds()
{
tld.insert(std::make_pair("XX", true));
}
And don't forget semicolon at the end of the class.
EDIT: You can provide in-class initializers for static members of const integral type or static members that are constexprs and has literal type.
I have the following code:
class gptr_timer {
private:
static qtimer_t gptr_get_timer;
public:
static void create_gptr_get_timer(){
gptr_get_timer = qtimer_create();
}
static void destroy_gptr_get_timer(){
qtimer_destroy(gptr_get_timer);
}
static void start_gptr_get_timer(){
qtimer_start(gptr_get_timer);
}
static void stop_gptr_get_timer(){
qtimer_stop(gptr_get_timer);
}
static double get_gptr_get_time(){
return qtimer_secs(gptr_get_timer);
}
};
Which produces the following compile error:
/home/knusbau2/barnes/qppl/gptr.h:24: undefined reference to `ppl::gptr_timer::gptr_get_timer'
I'm a little confused, as I clearly have gptr_get_timer defined.
By adding a definition:
class gptr_timer { /* ... */ }; // class definition;
// *delcares* static member variables
qtimer_t gptr_timer::gptr_get_timer; // *define* static member variables
The static member definition has to go into one single translation unit, while the class definition is usually in a header. Beware.
The member definition is also the place for initialization, except in a few special cases (namely static constant expressions) which can be initialized inside the class definition.
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.