I want to create a class one of whose private: members is a struct point(see below). The public members ndim and numparticles are
set at run-time by the user, which are used to create corresponding arrays inside the class . However I am getting a compiler error. I don't understand where I messed up.
The compiler error being displayed:
nbdsearch.h:25: error: ‘point’ does not name a type
nbdsearch.h:24: error: invalid use of non-static data member ‘nbdsearch::ndim’
nbdsearch.h:31: error: from this location
nbdsearch.h:31: error: array bound is not an integer constant before ‘]’ token
The class code:
class nbdsearch{
public:
int ndim,numparticles;
point particlevec[numparticles];
private:
struct point{
string key;
double cood[ndim];
};
};
nbdsearch.h:31: error: array bound is not an integer constant before ‘]’ token
double cood[ndim];
Array size needs to be a compile time constant and ndim clearly isn't. ndim is a variable.
error: ‘point’ does not name a type
point particlevec[numparticles];
On line 25, compiler doesn't know what point is. The structure is defined at a later point. Compilers in C++ work on a top to bottom approach(Not sure whether C++0X relaxes this rule). So, what ever types being used should be known to it before hand.
Try this -
class nbdsearch{
private:
struct point{
string key;
std::vector<double>cood;
};
public:
int ndim,numparticles;
std::vector<point> particlevec;
};
point needs to be declared before its use. Try putting the private: block before the public: block.
There are a few different problems with your code.
The declaration of point needs to be visible to compiler before
you use it
You're trying to create array from variables that are not compile time constants; C++ does not allow creation of variable length arrays.
To fix these problems:
Move the declaration block for point above where you use it. Note that since the definition of point is private, someone calling nbdsearch::particlevec will not be able to store that value. All they could do is pass it along to another member function (or friend function) of nbdsearch.
Change declaration of particlevec to std::vector<point> particlevec. Make a similar change for point::cood. Once the user specifies values for ndim & numparticles use std::vector::resize to size the arrays appropriately.
Related
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.
I am trying to have a declaration of 2d array in private part of my class and then latter on, the functions of this class will use and modify the values in the array, but I am getting an error which says "I-value specified const object". What is wrong with this code and how can I fix it?
Here is a simple code demonstrating my problem
in someClass.h________________
class someClass
{
public:
//Some code here
private:
char grid[20][20];
//Some code here
}
in someClass.cpp______________
lets say one of the functions is trying to reassign the value of item in position (0,0) like so.
grid[0][0]='*';
This gives me an error saying, expression must be modifiable lvalue.
Move it from private to public so you can access it outside the class. If it is private then only functions inside the class can use it.
Rather surprised to find this question not asked before. Actually, it has been asked before but the questions are VERY DIFFERENT to mine. They are too complicated and absurd while I'll keep it simple and to the point. That is why this question warrants to be posted.
Now, when I do this,
struct A {
int a = -1;
};
I get the following error:
ANSI C++ forbids in-class initialization of non-const static member a
Now, along with the workaround can someone please tell me THE BEST way of initializing a struct member variable with a default value?
First, let's look at the error:
ANSI C++ forbids in-class initialization of non-const static member a
Initialization of a true instance member, which resides within the memory of an instance of your struct is the responsibility of this struct's constructor.
A static member, though defined inside the definition of a particular class/struct type, does not actually reside as a member of any instances of this particular type. Hence, it's not subject to explaining which value to assign it in a constructor body. It makes sense, we don't need any instances of this type for the static member to be well-initialized.
Normally, people write member initialization in the constructor like this:
struct SomeType
{
int i;
SomeType()
{
i = 1;
}
}
But this is actually not initialization, but assignment. By the time you enter the body of the constructor, what you've done is default-initialize members. In the case of a fundamental type like an int, "default-initialization" basically boils down to "eh, just use whatever value was in those bytes I gave you."
What happens next is that you ask i to now adopt the value 1 via the assignment operator. For a trivial class like this, the difference is imperceptible. But when you have const members (which obviously cannot be tramped over with a new value by the time they are built), and more complex members which cannot be default-initialized (because they don't make available a visible constructor with zero parameters), you'll soon discover you cannot get the code to compile.
The correct way is:
struct SomeType
{
int i;
SomeType() : i(1)
{
}
}
This way you get members to be initialized rather than assigned to. You can initialize more than one by comma-separating them. One word of caution, they're initialized in the order of declaration inside your struct, not how you order them in this expression.
Sometimes you may see members initialized with braces (something like i{1} rather i(c)). The differences can be subtle, most of the time it's the same, and current revisions of the Standard are trying to smooth out some wrinkles. But that is all outside the scope of this question.
Update:
Bear in mind that what you're attempting to write is now valid C++ code, and has been since ratification of C++11. The feature is called "Non-static data member initializers", and I suspect you're using some version of Visual Studio, which still lists support as "Partial" for this particular feature. Think of it as a short-hand form of the member initialization syntax I described before, automatically inserted in any constructor you declare for this particular type.
You could make a default constructor
struct A {
A() : a{-1} {}
int a;
};
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);
};
So far I have used DEFINE to declare my constants. and it works perfectly fine.
I am trying to use the c++ const keyword in my classes but it gives compile time error
Header
class User{
public:
User::User();
protected:
const float DATA_Z;
}
.CPP
User::User(){
DATA_Z = 0.0023f;
}
this is the error it generates
Error 3 error C2758: 'User::DATA_Z ' : must be initialized in constructor base/member initializer list
How can I assign a data to it, and how can I use them in my class.
The error message is pretty clear. Move assignment into initializer list:
User::User(): DATA_Z(0.0023f)
{
}
You want to do this instead:
User::User() : DATA_Z(0.0023f)
{
// body of constructor
}
Constant members need to be initialized in the initializer list, because they cannot be assigned directly. The same is also true for members that are reference-type, because you cannot change the referent of a reference variable.
To simply replace manifest constants defined with #define, write global consts:
#define DATA_Z 0.0023f
becomes
const float DATA_Z = 0.0023f;
Putting the constants into the class means you can have a different value in each object, which is why the other answers tell you to initialize it in the constructor. That's a legitimate design decision, but it's different from defining the value as a macro.
The following code helps you to pass any value to initialize the DATA_Z:
`
class User{
public:
User::User(float data=0):DATA_Z(data){}; // here `data` is a local parameter to receive the assigned value.
protected:
const float DATA_Z;
}
`