how do I initialize a const int member in class constructor - c++

I would to initialize a const int member (numGrids) of my class TestCase when I construct a TestCase. It needs to be const (I think) because it defines the elements of another array member of the classwhich I would also like to initialize when I create a TestCase. The code is shown below:
/////////////////////////////////////////////////////////////////////////////////////
//TestCase.h
class TestCase
{
protected:
const int numGrids;
Grid meshes[numGrids];
public:
TestCase(const int);
};
/////////////////////////////////////////////////////////////////////////////////////
//TestCases.cpp
TestCase::TestCase(const int numGridsSpec)
{
numGrids = numGridsSpec;
Grid grids[numGrids];
}
I cannot seem to initialize the const member of my class. I need that member to be constant because it defines the array size of meshes. I get the following errors:
[ 12%] Building CXX object sources/CMakeFiles/GridRefinementStudy.dir/TestCase.cpp.o
In file included from /home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.cpp:16:0:
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.h:5:12: error: invalid use of non-static data member ‘TestCase::numGrids’
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.h:6:14: error: from this location
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.h:6:22: error: array bound is not an integer constant before ‘]’ token
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.cpp: In constructor ‘TestCase::TestCase(int)’:
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.cpp:25:1: error: uninitialized member ‘TestCase::numGrids’ with ‘const’ type ‘const int’ [-fpermissive]
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.cpp:28:13: error: assignment of read-only member ‘TestCase::numGrids’
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.cpp:29:21: error: no matching function for call to ‘Grid::Grid()’
/home/omar/Documents/Programming/C++/FCFD/Current/sources/TestCase.cpp:29:21: note: candidates are:
/home/omar/Documents/Programming/C++/FCFD/Current/sources/Grid.h:13:2: note: Grid::Grid(int, int, double, double)
/home/omar/Documents/Programming/C++/FCFD/Current/sources/Grid.h:13:2: note: candidate expects 4 arguments, 0 provided
/home/omar/Documents/Programming/C++/FCFD/Current/sources/Grid.h:1:7: note: Grid::Grid(const Grid&)
/home/omar/Documents/Programming/C++/FCFD/Current/sources/Grid.h:1:7: note: candidate expects 1 argument, 0 provided
make[2]: *** [sources/CMakeFiles/GridRefinementStudy.dir/TestCase.cpp.o] Error 1
make[1]: *** [sources/CMakeFiles/GridRefinementStudy.dir/all] Error 2
make: *** [all] Error 2

You may not do such a way. The size of the array shall be known at compile time. In fact you are trying to get a variable length array. C++ does not have such a feature.
Take into account that if the sizes of the array are different for two objects then the classes that define them are different types. They have different data members that is arrays with different sizes. The size of a class shall be the same for each object of that class.
I would suggest to use standard container std::dynarray if the compiler supports it or
std::vector
On the other hand you could define your class as a template class. For example
template <size_t numGrids>
class TestCase {
protected:
Grid meshes[numGrids];
//...
or even as
template <size_t numGrids>
class TestCase {
protected:
std::array<Grid, numGrids> meshes;
//...
I think that using a template class is the best approach in your case.

In pre-C++11, there are four ways of initializing a member:
If the member is static, const and has an integral type,
it can be initialized directly in the class definition. In this
case, the member is a "integral constant expression", and can be
used anywhere the compiler requires such (e.g. array dimensions,
template argument, etc.).
If the member is static, it must be initialized in its
definition. If the member is also const, it is a constant
expression in the translation unit which contains the
definition, after the definition.
Any member can be initialized in the initializer list, and
typically, all should be (but there are exceptions). Non-static
const members must be initialized here (but non-static const
members are not constant expressions, and cannot be used as
such).
Finally, non-const members can be "initialized" in the
constructor body. Formally, this is assignment, not initialization, and if
the member type has a user defined constructor, it will still be
initialized (using the default constructor) in the
initialization list. For primitive types, the member remains
uninitialized if it isn't mentionned in the initializer list,
until it is first assigned.
In your case, it would appear that you want an array whose size
is defined by a parameter to the constructor. This is not
possible; the size of an array must be an integral constant
expression. If the size should always be the same, then you can
use a static const int to define it:
class TestClass
{
static int const numGrids = 25;
Grid meshes[numGrids];
// ...
};
Otherwise, you'll have to use:
class TestClass
{
std::vector<Grid> meshes;
public:
TestClass( int size ) : meshes( size ) {}
};
This might be the better solution anyway.

First of all since numGrids is const in the class declaration, you can only initialize it through initialization list.
TestCase::TestCase(const int numGridsSpec)
:numGrids(numGridsSpec) // this is the initialization list
{
...
}
This is simply because a constant variable can only be set to a value once and can not be modified 'legally' thereafter, compilers normally would not allow you to proceed avoiding unexpected consequences in this case.

There's a mistake in your code. The array size is dynamic (a variable). You can't use a variable to declare an array size at compile time. Use some constants with real value.
To Answer your question
Initializer list is used to init the data for a const. Something as follows.
class TestCase {
protected:
const int numGrids;
public:
TestCase(const int x) : numGrids(x)
{
}
};
Solution for your problem
class TestCase {
protected:
const int numGrids;
Grid* pMeshes;
public:
TestCase(const int x) : numGrids(x)
{
pMeshes = new Grid[x];
}
~TestCase() : numGrids(x)
{
delete []pMeshes; // release allocated memory in destructor
}
};
int main(int argc, char* argv[])
{
TestCase t(10);
return 0;
}

If your compiler supports c++11, you could simply do:
class TestCase
{
protected:
const int numGrids = 25;
Grid meshes[numGrids];
public:
TestCase(const int);
};

Related

why use "static" keyword before public data member?

I have an integer data member called "students" in public part of my class and is used as an argument in the constructor.
gradebook.h:
class gradebook
{
public:
int students = 10;
gradebook(string, int[]);
void SetCourseName(string _coursename);
...
private:
string coursename;
...
};
gradebook.cpp:
#include "gradebook.h"
gradebook::gradebook(string s1, int array[students])
{
SetCourseName(s1);
}
void gradebook::SetCourseName(string _coursename)
{
coursename = _coursename;
}
when I try to compile the code receive this error:
invalid use of non-static data member 'gradebook::students'
gradebook::gradebook(string s1, int array[students])
^
if I put 'static const' before 'int student = 10' the problem gets away.
why?
This expression defines a stack-allocated array of a fixed length. The length of the array must be known at compile time:
int array[students]
adding the static keyword inlines the length of the array as a compile-time constant.
To allow in-class initialization as in your example you actually need to define the variable const and static as follows:
static const int students = 10;
You could find some details on arrays here http://www.cplusplus.com/doc/tutorial/arrays/
Addition: passing an array of fixed length as a parameter results in passing a pointer, the length is ignored. Therefore, you could simply omit the "length" of the passed array and use your in-class variable as a constant for iterating through the array.

invalid use of non-static data member while using const variable

class Try {
const int no = 5;
int arr[no];
};
Here is a simple class , but I get this compilation error. no is constant so I thought it should not be the problem.
arr must have the same size in all instances of your class. no is const but that only means it never changes after an instance is created. It doesn't mean that it is the same for all instances all the time. For example, no can be set in the initializer list of the constructor
Foo::Foo(int size) : no(size)
{}
For this reason, unless you make no static, you can't use it as array size because that would imply potentially differently sized arrays in each instance.

Static member array of pointers to member functions

I am trying to define in a .cpp file an attribute which should be an array of pointers to member functions of a class named Hand.
Both the array and the functions are members of Hand and the array is static(please correct me if it should not).
This is what I reached:
static bool Hand::*(Hand::hfunctions)[] ()=
{&Hand::has_sflush,&Hand::has_poker,&Hand::has_full,&Hand::has_flush,
&Hand::has_straight,&Hand::has_trio,&Hand::has_2pair,&Hand::has_pair};
I get this error: hand.cpp:96:42: error: declaration of ‘hfunctions’ as array of functions.
I guess the type definition is worng so I need to know how can I make the definition right
The syntax is a rather convoluted one:
class Hand
{
bool has_sflush();
static bool (Hand::*hfunctions[])();
...
};
bool (Hand::*Hand::hfunctions[])() = {&Hand::has_sflush, ...};
A way to get to this is by gradually increasing complexity, using cdecl.org to check yourself at each step:
int (*hFunctions)()
declare hFunctions as pointer to function returning int
int (Hand::*hFunctions)()
declare hFunctions as pointer to member of class Hand function returning int
Warning: Unsupported in C -- 'pointer to member of class'
int (Hand::*hFunctions[])()
declare hFunctions as array of pointer to member of class Hand function returning int
Warning: Unsupported in C -- 'pointer to member of class'
Now replace int by bool (sadly, cdecl.org doesn't understand bool); so you get the syntax of the declaration.
For the definition, replace hFunctions by Hand::hFunctions, and add the initialization part, like you did.
Both the array and the functions are members of Hand and the array is static(please correct me if it should not).
If I understand correctly what you are asking, you should not. You should abstract the operation as a base class, specialize it and hold the array as an array of pointers to the base class:
struct Match // need a better name
{
virtual bool matches() = 0;
virtual ~Match() = default;
};
struct MatchSFlush: public Match { ... };
class Hand
{
static std::vector<std::unique_ptr<Match>> matches;
};
If you have non static member functions with no arguments and returning bool you should write something like
typedef bool (Hand::*hfunction_non_static)();
hfunction_non_static f_non_static [] =
{
&Hand::has_sflush,
&Hand::has_poker,
.......
};
Hand h;
(h.*f_non_static[0])();
If you have static functions you should write something like
typedef bool (*hfunction_static)();
hfunction_static f_static [] = {&Hand::has_sflush, ....};
f_static[0]();

Unable to pass a reference of 'this' to a constructor of another class

We have a class CJ that upon it's creation, it creates a different class BA object to which it wants to pass a reference to itself like so:
BA:BA(const CJ& myCJRef);
The compiler always errors with:
error: uninitialized reference member BA::myCJRef
CJRef is defined in the BA class as class type CJ
Now amounts of &, * or neither does anything but cause the same error. Initializing is tough since the initialization of myCJRef requires passing two other classes but the it would point to the wrong object.
I'm a 'C' guy... this is confounding.
Thanks all!
Following the below answers I got to the point where I used this pointer to call methods in the CJ object, the real code follows:
InputPoolBufferAdapter::InputPoolBufferAdapter (CJpsMixerChannel& _CJ, int jitter, int maxBuffers, unsigned long maxBufferAge): myCJpsMixerChannel (_CJ)
{
myCJpsMixerChannel = _CJ;
myJitter = jitter; // assuming jitter will be the number of floats
myJitterCounter = 0;
myMaxBuffers = maxBuffers;
myMaxBufferAge = maxBufferAge;
myPopulateMetadataRequests = 0;
mySendDataReadyAlert = true;
clearBufferAdapterThreshhold = CLEAR_BUFFER_ADAPTER_THRESHHOLD;
};
void InputPoolBufferAdapter::returnDataBufferToPool (ChannelBuffer_t buf)
{
void CJpsMixerChannel::myCJpsMixerChannel->returnBufferToInputPool(ChannelBuffer_t *returnBuffer_p);
};
void InputPoolBufferAdapter::notifyDataAvailable ()
{
void myCJpsMixerChannel.notifyDestinationsDataAvailable(void);
};
void InputPoolBufferAdapter::bufferAdapterError (int a)
{
void &myCJpsMixerChannel.inputBufferAdapterError(int error_code);
};
I tried several things as you can see but it will not compile, the errors are:
InputPoolBufferAdapter.cpp: In member function ‘virtual void InputPoolBufferAdapter::returnDataBufferToPool(ChannelBuffer_t)’:
InputPoolBufferAdapter.cpp:33:50: error: expected initializer before ‘->’ token
InputPoolBufferAdapter.cpp: In member function ‘virtual void InputPoolBufferAdapter::notifyDataAvailable()’:
InputPoolBufferAdapter.cpp:38:32: error: expected initializer before ‘.’ token
InputPoolBufferAdapter.cpp: In member function ‘virtual void InputPoolBufferAdapter::bufferAdapterError(int)’:
InputPoolBufferAdapter.cpp:43:32: error: expected initializer before ‘.’ token
I am at a loss, any more ideas for this no longer 'confounded' but definitely 'befuddled' software guy (I can't believe after 25 years in 'C' embedded systems this has got me so screwed up!).
Thanks all
I need to guess a bit, but your class BA also has a member variable called myCJRef, right? Its type is const CJ&, just like the parameter. In that case, you need to do this:
BA::BA( const CJ& r ) : myCJRef( r )
{
// note: myCJRef = r; would not work here.
}
because you need to initialize the member variable. The error does not refer to the parameter of your ctor.
You should post some code.
Anyway, without using any C++11 syntax, this is the way I would go:
CJ::CJ() : BA(*this) { //CJ constructor here }
BA::BA(const CJ& myCJ) : myCJref(myCJ) { //BA constructor here }
Here i only wrote CJ and BA constructors. BA must have a data member
const CJ& myCJref
for this to work.
Presumably BA has a non-static member const CJ& myCJRef. A reference type object cannot be left uninitialized, so you need to make sure this reference is initialized by the constructor's member initialization list. So the definition of the constructor will look like so:
BA::BA(const CJ& myCJRef)
: myCJRef(myCJRef)
{
// ...
}
Everything after the : is the member initialization list. In this case, it says initialize the member myCJRef with the argument myCJRef (it's okay that they have the same name).

why C++ Initialization list is before brace?

I want to know what's difference in the following two class.
example 1:
class A
{
string name;
public:
A(const char* _name):name(_name){}
void print(){cout<<"A's name:"<<name<<endl;}
};
example 2:
class A
{
string name;
public:
A(const char* _name){name(_name);}
void print(){cout<<"A's name:"<<name<<endl;}}
why the example 1 is passed and the last one is wrong?
Thanks
In example 1 you initialize the string with the given value right away.
In example 2 you create an empty string first and assign it later on.
Despite some performance differences and ignoring possible differences due to copy constructor handling etc. it's essentially the same result.
However once you use a const member you'll have to use example 1's way to do it, e.g. I usually create unique IDs the following way:
class SomeObject
{
static unsigned int nextID = 0;
const unsigned int ID;
SomeObject() : ID(nextID++)
{
// you can't change ID here anymore due to it being const
}
}
The first example is an actual initialization. It has a number of advantages, including being the only way to set up const members, and having proper exception-safety.
The second example is not valid C++, AFAIK. If you had instead written name = name_, then this would just be normal assignment. Of course, this isn't always possible; the object might be const, or not have an assignment operator defined. This approach could also be less efficient that the first example, because the object is both default-initialized and assigned.
As for why the initializer list is before the constructor body; well, that's just the way the language has been defined.
That's just how the language is defined. The member initializers should be placed before the body of the constructor.
In the first example the member name is initialized with a ctr getting char * as parameter.
In the second case it is initialized with a default ctr at first and it gets value by the assignment operator (operator=) later. That's why it is wrong with your case that it is already constructed there so you can not use the ctr once again you could just use the assignment operator.
The reason is that name lookup works different in initializer lists and function bodies:
class A
{
std::string foo; // member name
public:
A(const char* foo) // argument name
: foo(foo) // member foo, followed by argument foo.
{
std::cout << foo; // argument foo.
}
};
If the initializer list was inside the function body, there would be an ambiguity between member foo and argument foo.
The motivation behind the initialization list is due to const field holding a object by value (as opposed to reference/pointer field).
Such fields must be initialized exactly once (due to their const-ness). If C++ didn't have initialization list then a ctor would look something like:
class A {
public:
const string s;
const string t;
A() {
// Access to either s or t is not allowed - they weren't initialized
s = "some-string";
// now you can access s but you can't access t
f(*this);
t = "some other string";
// From now you can access both ...
}
}
void f(A& a) {
// Can you access a.s or a.t?
cout << a.s << a.t;
}
Without an initialization list a ctor can pass a partially-initialized object of type A to a function, and that function will have no way of knowing which fields are initialized yet. Too risky and very difficult for the compiler/linker to check.