initializing a static (non-constant) variable of a class. - c++

I have TestMethods.h
#pragma once
// strings and c-strings
#include <iostream>
#include <cstring>
#include <string>
class TestMethods
{
private:
static int nextNodeID;
// I tried the following line instead ...it says the in-class initializer must be constant ... but this is not a constant...it needs to increment.
//static int nextNodeID = 0;
int nodeID;
std::string fnPFRfile; // Name of location data file for this node.
public:
TestMethods();
~TestMethods();
int currentNodeID();
};
// Initialize the nextNodeID
int TestMethods::nextNodeID = 0;
// I tried this down here ... it says the variable is multiply defined.
I have TestMethods.cpp
#include "stdafx.h"
#include "TestMethods.h"
TestMethods::TestMethods()
{
nodeID = nextNodeID;
++nextNodeID;
}
TestMethods::~TestMethods()
{
}
int TestMethods::currentNodeID()
{
return nextNodeID;
}
I've looked at this example here: Unique id of class instance
It looks almost identical to mine. I tried both the top solutions. Neither works for me. Obviously I'm missing something. Can anyone point out what it is?

You need to move the definition of TestMethods::nextNodeID into the cpp file. If you have it in the header file then every file that includes the header will get it defined in them leading to multiple defenitions.
If you have C++17 support you can use the inline keyword to declare the static variable in the class like
class ExampleClass {
private:
inline static int counter = 0;
public:
ExampleClass() {
++counter;
}
};

Related

Why Do I get this error on vector initialisation?

I have a problem with vector declaration and initialization in a
class constructor. I have a Station.h and Station.cpp files of a class and I recall it in main :
Station.h
#ifndef STATION_H
#define STATION_H
#include <vector>
class Station
{
public:
int num_bin;
int num_staz;
vector<int> binari; //here already gives me error! Vector does not name a type
Station(int num_staz, int num_bin);
virtual ~Station();
Station(const Station& other);
protected:
private:
};
Then I want to initialize the vector in the constructor of .cpp like that:
Station.cpp
#include "Station.h"
using namespace std;
Station::Station(int num_staz, int num_bin)
{
this->num_bin = num_bin;
this->num_staz = num_staz;
this->binari(num_bin); //here I want to create a vector of num_bin size
}
and then call it in main like that:
main.cpp
#include <iostream>
#include "Station.h"
using namespace std;
int main()
{
Station staz1(2,3);
staz1.binari.push_back(300); // error! class Station has no member binari
staz1.binari.push_back(250);
staz1.binari.push_back(150);
return 0;
}
Where am I making a mistake?
this->binari(num_bin); //here I want to create a vector of num_bin size
The function you need to use is std::vector::resize().
this->binari.resize(num_bin);
It will be better to initialize the object with the appropriate size as:
Station::Station(int num_staz, int num_bin) : num_bin(num_bin),
num_staz(num_staz),
binari(num_bin)
{
}
this->binari(num_bin); This doesn't work because it is not an initialization that is why it doesn't work.
To make this work use it in in-class initialization list:
Station::Station(int num_staz, int num_bin) :
num_bin(num_bin),
num_staz(num_staz),
binari(num_bin)
{
}

Function was not declared in this scope, even though header file is present

I'm trying to run some test code to learn c++, but I am getting an error telling me the reverseDigits function was not declared in the main.cpp scope:
error: 'reverseDigits' was not declared in this scope.
But the #include "Solutions.h" header was included in main.cpp, so I thought that it would be in scope.
I have checkout other questions, but the answers all relate to problems with circular header file inclusion, which I don't think is the problem here.
Do you know why I am seeing that error?
Solution.h
#ifndef SOLUTION_H
#define SOLUTION_H
class Solution {
public:
Solution();
~Solution();
int reverseDigits(int x);
};
#endif // SOLUTION_H
Solution.cpp
#include "Solution.h"
#include <string>
Solution::Solution()
{
}
Solution::~Solution()
{
}
int Solution::reverseDigits(int x) {
std::string num_string = std::to_string(x);
std::string reversed_num_string {};
for (int i = num_string.length() - 1; i > 0; i--) {
reversed_num_string.push_back(num_string[i]);
}
return stoi(reversed_num_string);
}
main.cpp
#include <iostream>
#include "Solution.h"
int main()
{
int x {123};
int result = reverseDigits(x);
std::cout << result << std::endl;
return 0;
}
You declared reverseDigits as a member function of the Solution class, then defined it without qualifying it as a member of Solution (Edit: You've since changed it to match declaration and definition, but at point of use, you're trying to use an unqualified function, not a member of a Solution object). The declaration in the .h file is visible, but the definition in the .cpp is unrelated, and not visible to main.cpp.
Declare the function outside the class (since it's clearly unrelated to the class), and it should work, changing to:
class Solution {
public:
Solution();
~Solution();
};
int reverseDigits(int x); // NOT inside the class definition
I'll note: I have no idea why you have a Solution class at all. Defining reverseDigits doesn't require it, so I'm not seeing the point. If this is part of some automated evaluation framework, you'll have to give more details
Along with ShadowRanger's valid suggestion, I'll highlight upon how you could have used the data as part of your Solution class and applied the function on it.
Refactoring your class to
class Solution {
public:
Solution(int data);
~Solution();
int reverseDigits();
private:
int m_data;
};
Solution::Solution(int data)
{
m_data = data;
}
Solution::~Solution()
{
}
Even though you could have used std::reverse, fixing the error on the i>=0 is needed to have your own reverse function
int Solution::reverseDigits() {
std::string num_string = std::to_string(m_data);
std::string reversed_num_string {};
for (int i = num_string.length() - 1; i >= 0; i--) {
reversed_num_string.push_back(num_string[i]);
}
return stoi(reversed_num_string);
}
Now call it from your main() as
int main() {
int x = 123;
Solution sol(x);
std::cout << sol.reverseDigits() << std::endl;
return 0;
}

Enum in a class with strings

I'm trying to implement a class (C++) with an enum (with the permitted parameters). I got a working solution, but if I try to extend the functionality I get stuck.
Header data_location.hpp
class DataLocation
{
private:
public:
enum Params { model, period };
std::string getParamString(Params p);
};
Program data_location.cpp
string DataLocation::getParamString(Params p){
static const char * ParamsStrings[] = {"MODEL", "PERIOD"};
return ParamsStrings[p];
}
The array ParamsStrings should be generally available in the class, because I need a second method (with inverse function) returning the enum value given a string.
If I try to define the array in the header I get the error:
in-class initialization of static data member ‘const char* DataLocation::ParamsStrings []’ of incomplete type
Why is the type incomplete? The compiler is for sure able to counts the strings in the array, isn't it?
In case there is no way to get my code working, is there an other way? With 1) no XML; 2) no double definition of the strings; 3) not outside the class; 4) no in code programmed mapping.
In class (header) use keyword static and initialize it outside (.cpp) without the static keyword:
class DataLocation {
public:
enum Params { model, period };
string getParamString(Params p);
static const char* ParamsStrings[];
// ^^^^^^
};
const char* DataLocation::ParamsStrings[] = {"MODEL", "BLLBLA"};
//^^^^^^^^^^^^^^^^^^^^^^^^
The code you have posted is perfectly fine.
Here's the proof:
#include <iostream>
#include <string>
struct DataLocation
{
enum Params { model, period };
std::string getParamString(Params p){
static const char * ParamsStrings[] = {"MODEL", "PERIOD"};
return ParamsStrings[p];
}
};
int main()
{
auto a = DataLocation();
std::cout << a.getParamString(DataLocation::model) << std::endl;
return 0;
}
The error message you are getting is not to do with definition of a static data member in an inline function - that's allowed.
There's something else you're not showing us.
The main issue in my question (the second part) was that if I split the class in .hpp and .cpp the definition of the array (I mixed *char and string) has also to be split:
// data_location.hpp
class DataLocation {
static const char * ParamsStrings[];
}
// data_location.cpp
const char * ParamsStrings[] = {"MODEL", "PERIOD"};
At the end I introduced a consistency check to be sure that the number of values in enum growths as the number of strings. Because the array in C++ is somehow limited I had to go for a std::vector (to get the size).
Code for data_location.hpp
#ifndef DATA_LOCATION_HPP_
#define DATA_LOCATION_HPP_
#include <string>
#include "utils/dictionary.hpp"
extern const char* ENV_DATA_ROOT;
struct EDataLocationInconsistency : std::runtime_error
{
using std::runtime_error::runtime_error;
};
struct EDataLocationNotValidParam : std::runtime_error
{
using std::runtime_error::runtime_error;
};
class DataLocation
{
private:
std::string mRootLocation;
static const std::vector<std::string> msParamsStrings;
static bool msConsistenceCheckDone;
public:
DataLocation();
std::string getRootLocation();
std::string getLocation(Dictionary params);
enum Params { model, period, LAST_PARAM};
std::string Param2String(Params p);
Params String2Param(std::string p);
};
#endif
Code for data_location.cpp
#include "data_location.hpp"
#include <string>
#include <cstdlib>
using namespace std;
const char* ENV_DATA_ROOT = "DATA_ROOT";
bool DataLocation::msConsistenceCheckDone = false;
DataLocation::DataLocation() {
mRootLocation = std::getenv(ENV_DATA_ROOT);
if (not msConsistenceCheckDone) {
msConsistenceCheckDone = true;
if (LAST_PARAM+1 != msParamsStrings.size()) {
throw(EDataLocationInconsistency("DataLocation: Check Params and msParamsStrings"));
}
}
}
string DataLocation::getRootLocation() {
return mRootLocation;
}
string DataLocation::getLocation(Dictionary params) {
// to do
return "";
}
const vector<string> DataLocation::msParamsStrings = { "MODEL", "PERIOD", ""};
string DataLocation::Param2String(Params p) {
if (p>=msParamsStrings.size()) {
throw(EDataLocationNotValidParam("Parameter not found"));
}
return msParamsStrings[p];
}
DataLocation::Params DataLocation::String2Param(string p) {
for (int i = 0; i < msParamsStrings.size(); i++) {
if (p == msParamsStrings[i])
return (Params)i;
}
throw(EDataLocationNotValidParam("Parameter not found"));
}
And also a unit test:
#include <boost/test/unit_test.hpp>
#include "data_location.hpp"
#include <string>
using namespace std;
BOOST_AUTO_TEST_SUITE( data_location )
BOOST_AUTO_TEST_CASE(data_location_1) {
DataLocation dl;
auto s = dl.getRootLocation();
BOOST_CHECK_EQUAL(s, "/home/tc/data/forex" );
BOOST_CHECK_EQUAL(dl.Param2String(DataLocation::period),"PERIOD");
BOOST_CHECK_EQUAL(dl.String2Param("PERIOD"),DataLocation::period);
BOOST_CHECK_THROW(dl.String2Param("SOMETHING"), EDataLocationNotValidParam);
BOOST_CHECK_THROW(dl.Param2String((DataLocation::Params)100), EDataLocationNotValidParam);
}
BOOST_AUTO_TEST_SUITE_END()
C++ is very picky about what it will let you initialize inside of a class definition; there are some particularly non-intuitive rules surrounding static members. It all has to do with the ODR, and why all the rules are the way they are is not especially important.
To cut to the chase, making your array a static constexpr const member should shut the compiler up. With the C++11 standard, the restrictions were relaxed a bit, and one of the new stipulations was that static constexpr members can be initialized inline. This is perfect for your application, since the strings in your array are compile-time constants.
The recent g++ compiler which support C++0x or later compiles thus code. Pure C compile compiles, too. Because strings in initialization like {"MODEL", "PERIOD"}; implemented as const char * pointer to the char array.

Initialize static variables declared in header

I'm changing the class implementation of a large class for a company project that has several static variables declared as private members of the class. There are many arrays and structs declared in the class header that utilize these static variables. I now need to assign the static data members values from my main function somehow. I tried assigning the static variables through the constructor but the header is declared prior to the constructor call so that wasn't possible.
For example, if I have
class Data
{
private:
static unsigned int numReadings = 10;
static unsigned int numMeters = 4;
unsigned int array[numMeters];
}
I would want to change it such that I could set numReadings and numMeters from my main function somehow, so it will allow all of my arrays and structs that utilize numMeters and numReadings to be initialized properly.
Is there a way to do this in C++? Of course I could always change my class design and set these in the constructor somehow but I'd like to avoid that if I can as it will take quite a long time.
You cannot do it in the main function, but you can do it in the main.cpp file:
// Main.cpp
#include <iostream>
#include "T.h"
using namespace std;
int T::a = 0xff;
int main()
{
T t; // Prints 255
return 0;
}
// T.h
#pragma once
#include <iostream>
using namespace std;
class T {
public:
T() { cout << a << endl; }
private:
static int a;
};
Have you tried making them public and accessing them with Data::numReadings = 10?
UPDATE:
#include <cstdlib>
using namespace std;
/* * */
class Asdf
{
public:
static int a;
};
int Asdf::a = 0;
int main(int argc, char** argv) {
Asdf::a = 2;
return 0;
}
Regardless of the accessibility of these variables, you need to define and initialize the static members outside the class definition:
// header
class Data
{
private:
static unsigned int numReadings;
static unsigned int numMeters;
unsigned int array[numMeters]; //<=see edit
};
// class implementation file
unsigned int Data::numReadings = 10;
unsigned int Data::numMeters = 4;
This is part of the implementation of the class and shouldn't be in the header (ODR rule).
Of course, if you want to access these variables (which are shared among all instances of the class) from outside, you need to make them public, or better, foresee and accessor.
Edit:
As the question is formulated around the static issue, I didn't notice the variable length array : this is not standard c++, although some compilers might accept it as a non-standard extension.
To do this properly, you should define a vector and initialize it at construction:
class Data
{
public:
Data ();
private:
static unsigned int numReadings;
static unsigned int numMeters;
vector<unsigned int> mycontainer; //<=for dynamic size
};
Data::Data() : mycontainer(numMeters) { } // initialize object with right size

Calling a method from a constructor in another class c++

I need to call a method from one class in the constructor of another class. I am not sure how to do this without getting a "was not declared in this scope" error. Note I am just learning C++.
See the comments in symboltable.cpp for what I am trying to accomplish here. I am not looking for anyone to do it for me. I could use an example or pointed in the right direction so I can figure this out.
symboltable.h code:
class SymbolTable
{
public:
SymbolTable() {}
void insert(string variable, double value);
void insert(string variable); // added for additional insert method
double lookUp(string variable) const;
void init(); // Added as mentioned in the conference area.
private:
struct Symbol
{
Symbol(string variable, double value)
{
this->variable = variable;
this->value = value;
}
string variable;
double value;
};
vector<Symbol> elements;
};
symboltable.cpp code:
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
#include "symboltable.h"
/* Implementing the "unreferenced variable" warning.
* Modify the symbol table by adding another insert method
* that supplies only the variable name.
* This method should be called when the variable name
* is encountered while building the arithmetic expression tree.
* It would be called in the constructor of the Variable class.
* The existing insert method, which is called when an assignment is encountered,
* would first check to see whether it is already in the symbol table.
* If it is not, then it is unreferenced.
*/
void SymbolTable::insert(string variable, double value)
{
/* This existing insert method, which is called when an assignment is encountered,
* first needs to check to see whether it is already in the symbol table.
* If it is not, then it is unreferenced.
* */
//Need to check if variable is in the expression need to find out how the expression is stored!
if (find(elements.begin(), elements.end(), variable)) {
const Symbol& symbol = Symbol(variable, value);
elements.push_back(symbol);
} else
throw string("Error: Test for output");
}
/* Adding another insert method that supplies only the variable name.
* This method should be called when the variable name is encountered
* while building the arithmetic expression tree.
* It should be called in the constructor of the Variable class.
*/
void SymbolTable::insert(string variable)
{
const Symbol& symbol = Symbol(variable, symbolTable.lookUp(variable));
elements.push_back(symbol);
}
double SymbolTable::lookUp(string variable) const
{
for (int i = 0; i < elements.size(); i++)
if (elements[i].variable == variable)
return elements[i].value;
else
throw "Error: Uninitialized Variable " + variable;
return -1;
}
void SymbolTable::init() {
elements.clear(); // Clears the map, removes all elements.
}
variable.h code:
class Variable: public Operand
{
public:
Variable(string name) //constructor
{
// how do i call symbolTable.insert(name); here
// without getting 'symboleTable' was not declared in this scope error
this->name = name;
}
double evaluate();
private:
string name;
};
variable.cpp code:
#include <string>
#include <strstream>
#include <vector>
using namespace std;
#include "expression.h"
#include "operand.h"
#include "variable.h"
#include "symboltable.h"
extern SymbolTable symbolTable;
double Variable::evaluate() {
return symbolTable.lookUp(name);
}
There are two solutions:
You use a global variable - like your Variable::evaluate() example. You can of course add your Variable::Variable() as a function in "variable.cpp" instead of the header. Or you can just put a extern SymbolTable symbolTable to the file "variable.h".
You pass in a reference to symbolTable into the constructor (and perhaps store that inside the Variable object - that way, symbolTable doesn't need to be a global variable at all.
By the way, it's generally considered bad style to add using namespace std before header files.
extern SymbolTable symbolTable; needs to go into the header file that is included by everyone who needs symbolTable. Then, in variable.cpp, you need to have SymbolTable symbolTable;
You need to instantiate the second class, either within the constructor, which will make it and its members available only within the constructor of the first class, or in the global namespace. For example:
MyFooClass CFoo;
MyBarClass CBar;
MyFooClass::MyFooClass()
{
CBar = new MyBarClass();
CBar.BarClassMemberFunction();
}