why use "static" keyword before public data member? - c++

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.

Related

declare a constant variable in a struct causes me this error a nonstatic member reference must be relative to a specific object

Hallo I am trying to declare an array in a struct and when I declare the size as a constant variable it shows me this error
a nonstatic member reference must be relative to a specific object
and if I declare the constant variable out of the struct scope the error goes away.
here is my code:
struct Student{
string name;
string birthday;
int studyYear;
string Faculty;
string Department;
const int MaxNrOfCrs = 10; // here is my error
const int Grade = 1; // The same error appears here also
Course crs[MaxNrOfCrs][Grade];
bool payment;
};
but when I try to take the two constants out of the struct Student scope the error does not appear any more
const int MaxNrOfCrs = 10; // The error vanishes here
const int Grade = 1; // The same error vanishes here also
struct Student{
string name;
string birthday;
int studyYear;
string Faculty;
string Department;
Course crs[MaxNrOfCrs][Grade];
bool payment;
};
Even though a class member is declared const with a default value, it can still be constructed in each individual instance of the class with some different value, via a constructor or, as in this case, aggregate initialization, perhaps.
Temporarily removing the invalid array declaration, here's some valid C++:
#include <string>
using namespace std;
struct Student{
string name;
string birthday;
int studyYear;
string Faculty;
string Department;
const int MaxNrOfCrs = 10; // here is my error
const int Grade = 1; // The same error appears here also
bool payment;
};
Student s{"John", "1/1/2000", 2017, "Engineering", "Mechanical",
20, 5, true};
So, this ends up constructing a class instance with MaxNrOfCrs containing 20.
So, what do you propose the size of your class array member to be here? It can't be different for every instance of the class, obviously.
Here, a const only means that this class member is constant after an instance of this class is constructed. And it can be constructed with any value, therefore you can't really use this class member to specify the immutable size of an array (there are a few other reasons too).
In the other case, you declared a global const int. End of story. Nothing could possibly change that. Hence you can use it to specify the size of some array.

Problems returning an object in C++

I'm just starting out in C++ and I'm having problems with one part of my assignment:
class Something {
public:
Random& random(); // should access a data member of type Random
private:
Random test(int r, int c);
}
Random& Something::random() {
return (Random&) test;
}
And now there's an error with "test" in the function definition of random(), because "the expression must be an lvalue" and I built the solution and the error message given says "'&' : illegal operation on bound member function expression "
I have to keep the function declaration the way it is, because it's listed that way in the specs.
How do I fix this?
You said in a comment: "test" is supposed to be a member variable.
Then, you need to change your class to:
class Something {
public:
Random& random(); // should access a data member of type Random
private:
// Not this. This declares test to be member function.
// Random test(int r, int c);
// Use this. This declares test to be member variable.
Random test;
}
Random& Something::random() {
return test;
}

how do I initialize a const int member in class constructor

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);
};

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]();

calling a function within a class in c++?

class CBAY_ITEM
{
public:
string name = enterName();
string condition = enterCondition();
};
when I compile, it gives 4 errors, which say
1.a function call cannot appear in a constant-expression
2.ISO C++ forbids initialization of member 'name'
3.making 'name' static
4.invalid in-class initialization of static data member of non-integral type 'std::string'
what am I doing wrong here??
You cannot initialize members at their declaration in C++03, unless they are static const members being initialized with constant expressions. Constant expressions cannot contain function calls in C++03.
Either switch to C++11 (-std=c++11 or -std=c++0x with gcc or clang) or initialize the members in the CBAY_ITEM's constructor. If you have several constructors that perform a common initialization, you can move the common initialization to a helper init method.
class CBAY_ITEM {
std::string name;
std::string condition;
public:
CBAY_ITEM() : name(enterName()), condition(enterCondition())
{}
};
Do you want to initialize those values in your class? Use a constructor.
#include <string>
std::string enterName();
std::string enterCondition();
class CBAY_ITEM
{
public:
std::string name;
std::string condition;
CBAY_ITEM() {
name = enterName();
condition = enterCondition();
}
};