In C++ how do I make a variable constant but assign to it in a constructor? The reason I want to do this is because I'm trying to use data driven design by putting all my data into an XML file and then loading that data into variables. The problem is that I can't load the values in a initialization list so I have to do it in the constructor (or elsewhere), but then the variables aren't constant.
Here's an XML file:
<weapons>
<pistol>
<damage>5.0</damage>
...
</pistol>
...
</weapons>
Then I've got a class like:
header
class Weapon
{
public:
Weapon();
const float damage;
};
source
#include "Weapon.h"
Weapon::Weapon()
{
//load damage value into damage variable
}
Because the damage variable is constant I can't do anything with it in the constructor, only in the initializer list, but obviously I can't execute code like reading an XML file in the initializer list. So even though the variable will never change should I just not make it constant or is there a proper way to leave it constant and do what I need?
Use an initializer-list:
#include "Weapon.h"
Weapon::Weapon() : damage(3.4)
{
}
You could have a xml parser, for example:
class WeaponXMLParser
{
public:
WeaponXMLParser(const std::string& filename);
float getDamage();
};
Initialize const member in initializers list:
Weapon::Weapon(const WeaponXMLParser& wxp) : damage(wxp.getDamage())
{
}
The body of the constructor indeed runs too late, your const members already have a value. that comes from the initializer list :
Weapon::Weapon()
: damage(0.0f) // 0.0f is the default value
{
}
In your case, you'd have to get it from the XML file, e.g.
float Weapon::LoadDmgFromXML();
Weapon::Weapon()
: damage(LoadDmgFromXML())
{
}
One approach is to use a "builder" class. So in your case you might have WeaponBuilder with appropriate methods that lets you do this:
WeaponBuilder wb(xmlFilename);
Weapon w(wb);
Then everything will be available in Weapon's constructor, so that you can make appropriate things const.
you must do it in initializer list. And you can provide a function that will determine what damage is and returns it, so you can set your const variable:
class Weapon
{
public:
Weapon():damage(damage_xml()){}
const float damage;
private:
float damage_xml();
};
You could use const_cast and make a non-const reference to the const variable.
float &_damage = const_cast<float&>(damage);
_damage = 12.34;
Related
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;
}
`
I'm making use of a class with a few utilities defined as static methods eg.
QDate SSIMUtils::ConvertSSIMDate(QString s) {
QDate rtnDt;
//...conversion code
return rtnDt;
}
I would like to define a few constants in this class eg. LOW_DATE and was thinking of putting in something like
const static QDate LOW_DATE; // Need to set this somewhere to 1/1/1970
Unfortunately, I can't define it pre-compile time like I would say an int eg.
const static int SSIMUtils::myI = 4;
because it requires the use of a setDate method.
My question is how should I define a static const that I need to set up codewise, as the constant requires initialisation. I'd been thinking of defining it in the .h file eg.
const static QDate LOW_DATE;
then in the .cpp file, at the top, doing something like
SSIMUtils::LOW_DATE.setDate(1970,1,1);
But this is syntactically incorrect. What I'd ultimately like to do is use this constant in other classes eg.
if (myQDate.compare(SSIMUtils::LOW_DATE)==0) {
// do something.
}
What's the right way to set up a constant value in a static class that you need to adjust at run time ie. like a constructor?
As I mentioned in a comment, QDate has a constructor equivalent to setDate(), which allows for initialisation of a 'const' object.
You must declare your static constant the following way:
myclass.h:
#include <QDate>
class myclass {
public:
const static QDate CONST_DATE;
};
myclass.cpp:
#include "myclass.h"
const QDate myclass::CONST_DATE(1970, 1, 1);
I tested this using a std::string instead of a QDate (no QT available right now), and it works just as you want.
It depends on where the necessary information for the
initialization comes, or rather, when it is available. If it's
always available, and the type supports copy, then you can
just write a function which returns the initialized type:
namespace {
MyType getInitialized()
{
MyType results;
// ...
return results;
}
}
static MyType const lowDate( getInitialized() );
If it doesn't support copy, you can derive from it, providing
a specialized constructor:
class MyTypeInitialized : public MyType
{
public:
MyTypeInitialized()
{
// ...
}
};
MyTypeInitialized lowDate;
This has the disadvantage of masking the true type from the
client code, but otherwise works well.
If the information isn't available until later; e.g. it depends
on command line arguments, then you may have to use a variant of
the singleton idiom, where you have two instance functions:
one of which takes the necessary arguments for initialization,
and must be called first. (Or that may even be overkill; it
might be sufficient to have a global std::unique_ptr<MyType
const> lowDate;, and initialize that with an object newed at
the start of main. The main different is in the client
syntax.)
You cannot change something declared constant at run-time, by definition.
The closest you can get to run-time constant initialization is to initialize in a class'
constructor initializer list:
SomeClass(int constantValue) :
myConstant(constantValue)
{
...
}
Given that you are building a static class, you are probably not constructing an object though. You can always resort to having a setter method which only allows setting the value once (in which case you can not declare the field const, obviously).
As the name implies, it is a constant, it cannot (should not) be changed once initialised. The only place that you can assign a value to a constant member variable is in the constructor (that is, without weird const_casts).
Your QDate may be trivial to construct -- using a static constant may not be better than creating a new date for that constant each time the function is called.
In the interest of answering the question, let's assume it is complex to construct and that a static constant is best idea. You can simply write:
QDate SSIMUtils::ConvertSSIMDate(QString s) {
static const QDate LOW_DATE( /* ...construct it... */ );
QDate rtnDt;
//...conversion code
return rtnDt;
}
Note: Looks like SirDarius explained how you can construct this type directly, without an intermediate (+1), although a function-local static constant is generally much better than a global constant because global constants lead to some very tough initialization problems in C++.
This creates a function local static which will be initialized once, and in a thread safe manner before it is read and when the function is called.
If the instance cannot be constructed easily, it helps at times to initialize using the copy constructor and then creating an accessory function:
QDate SSIMUtils::ConvertSSIMDate(QString s) {
struct F { static QDate Low() { return ...; } };
static const QDate LOW_DATE(F::Low()); // << initialize the constant using the copy ctor
QDate rtnDt;
//...conversion code
return rtnDt;
}
So the short approach using the construction provided by SirDarius using a function-local-static is:
QDate SSIMUtils::ConvertSSIMDate(QString s) {
static const QDate LOW_DATE(1970, 1, 1);
QDate rtnDt;
//...conversion code
return rtnDt;
}
When it comes to creating classes I've been told NO public data members. That's fine and I understand why but here's my issue. I've got a struct that I am using in a class (Linear linked list). I'd really like to initialize one of the struct fields (an array) to NULL so that I can check that the client is passing me valid structs, not uninitalized one's that are full of garbage values. I realize c++ won't let me set a default value in the struct declaration, so how do I protect from the client giving me garbage?
struct task {
char *description;
char *name;
float time_remaining;
float time_spent;
};
Then in my class I'm trying to do something like:
//I am making a copy of "to_add" and storing it in the LLL
int list::add_to_list(const task & to_add)
{ /.../ }
I don't want the user adding a bunch of uninitialized "task's" to the linked list... What to do? When I turned that struct into a class and moved the data members to private I had a TON of issues trying to access the data members to make copies of them. I was very careful not to do anything to effect the value of the var's but I couldn't get away from the compiler giving me errors about "error: passing ‘const task’ as ‘this’ argument of ‘char* task::get_comp_name()’ discards qualifiers [-fpermissive]" ("get_comp_name") was one of the getter's that I was sure wasn't editing any values, just passing me a copy) Please help me before I shoot myself. In the face.
In C++ a struct and a class are the same except for access control. So the struct's default access to members and inheritance is public, whereas the class' one is private. So you can give your struct a defult constructor and others to initialize it.
struct task {
task() : desctiption(0), name(0), time_remaining(0.), time_spent(0.) {}
char *description;
char *name;
float time_remaining;
float time_spent;
};
One side-effect of adding a constructor is that the struct isn't an aggregate anymore. This may or may not be an issue for you.
In C++11, you are also able to initialize members at the point of declaration:
struct task {
char *description{nullptr};
char *name{nullptr};
float time_remaining{0};
float time_spent{0};
};
This in-place initialization accepts type x = y syntax too, and argument-less {} initialization results in value initialization, which results in zero initialization for primitive types, so the arguments in the example could have been omitted.
There are several issues at hand here.
Public or not Public ?
Public attributes can seem handy, but they usually come back to bite you when you least expect it. I already suspect an issue with the time_remaining and time_spent: I suppose that both are modified quite at the same moment, aren't they ?
By default, variable attributes should be private, so that the class may enforce invariants such as time_remaining + time_spent is a constant throughout the lifetime of the task.
It is fine for constant attributes to be public, their role in invariants is settled once and for all in the constructor anyway.
But the weird errors message ?
This is because you lack a good tutorial or book. The problem at hand is quite simple: it is a const-ness related issue.
A const object may only be passed by const-reference or value to functions/methods and only const methods may be called on it. In your case, the proper declaration of the name() method should have a const qualifier after the method name.
Putting it altogether
And throwing in std::string because it's so much easier to manipulate.
class Task {
public:
Task(): time_remaining(0), time_spent(0) {}
Task(std::string name, std::string desc, float duration):
_name(name), _desc(desc), _time_remaining(duration), _time_spent(0) {}
// Accessors
std::string const& name() const { return _name; }
std::string const& description() const { return _desc; }
float time_remaining() const { return _time_remaining; }
float time_spent() const { return _time_spent; }
// Modifiers
void spend(float duration) {
_time_remaining -= duration;
_time_spent += duration;
}
private:
std::string _name, _desc;
float _time_remaining, _time_spent;
}; // class Task
Note: it could probably be beneficial to check that the duration passed to the spend method is not superior to the _time_remaining attribute, otherwise you spend more than you have...
Implement a constructor for the struct:
struct task {
task() : description(0), name(0), time_remaining(0), time_spent(0) {}
char *description;
char *name;
float time_remaining;
float time_spent;
};
The only difference between a class and a struct in C++ is the default accessibility of it's members.
I was looking for a method to initialize a static float inside a structure BUT using the constructor of the struct. In this site there are already solution to initialize the value but I was unable to find a solution that explicitly use the constructor.
The idea is the following:
struct test {
static const float a;
int b;
test(int bb, float a);
};
test::test(int bb, float aa) {
b=bb;
a=aa;
}
int main() {
int bval=2;
float aval=0.25;
struct test aaa(bval, aval);
return 0;
}
How to implement it correctly? Thank you for any advice.
You can't initialise it other than
const float test::a = something;
Outside the class (in a single compilation unit). However, you can do what you wrote and that will set the variable to the value you pass.
If you're wanting to set it only on the first time the constructor is entered, you can (but shouldn't) do something like
test::test(int bb, float aa){
static float _unused = (test::a = aa);
b=bb;
}
But that doesn't initialise it, it just assigns a value to it, and you'll still have to pass the variable to the constructor every time and nothing will be done with it (unless you give it a default value or something). That is a really terrible design though, it's probably better just to have a static function in the class to set the variable.
Static members are not associated with a particular instance, so they will only ever be initialised once. Constructors on the other hand are invoked on a per-instance basis, so it doesn't make sense to do what you're trying to do.
You can, on the other hand, assign a new value to static members in a constructor, as you're doing above, but you still have to actually initialise the static member outside the struct in the normal manner beforehand.
It's worth observing in passing that other languages (e.g. Java) have the concept of a static constructor for exactly this sort of thing - but C++ doesn't.
That said, you might find the following question interesting:
static constructors in C++? I need to initialize private static objects
You can't initialize a static const var inside constructor.
You should initialize at declaration
static const float a = 3.1416f;
Ensure you understand const keyword.
And should be integral.
Hi I was trying to define a constant inside a class, doing it the normal or usual way doesnt seem to work
class cat
{
public:
cat();
~cat();
private:
static const int MAX_VALUE = -99999;
int Number;
public:
void OrganizeNumbers();
void SetNumbers();
};
So the solution I found after doing some research was to declare it as static but what does this means and also I want to ask it is really necesary to declare a constant, becuase as you can see it is private right? i means it can only be accessed by the class methods so why to set a constant and also I read that using static only allows you to use integral type so its actually a dissavantage... if you are thinking to make a game.
static means that the member will be shared across all instances of your object.
If you'd like to be able to have different values of a const member in different instances you'll need to use a initialization list to set it's value inside your constructor.
See the following example:
#include <string>
struct Person {
Person (std::string const& n)
: name (n)
{
// doing: 'name = n' here is invalid
}
std::string const name;
};
int main (int argc, char *argv[]) {
Person a ("Santa Claus");
Person b ("Bunny the Rabbit");
}
Further reading
[10] Constructors - parashift.com/cpp-faq
10.1 Construct Initialization List
Initialization Lists in C++
1) Declare it "private" if you're only going to use MAX_VALUE inside your class's implementation, declare it under "public" if it's part of your class's interface.
2) Back in "C" days, "static" was used to "hide" a variable from external modules.
There's no longer any need to do this under C++.
The only reason to use "static" in C++ is to make the member class-wide (instead of per-object instance). That's not the case here - you don't need "static".
3) The "const" should be sufficient for you.
4) An (older-fashioned) alternative is to define a C++ enum (instead of a "const int")
There seems to be some confusion of ideas here:
A static member doesn't have to be an integral type, the disadvantage you mention does not exist.
const and private are unrelated, just because a member can only be accessed from instances of a given class, doesn't mean that nothing is going to change it.
Being const-correct guards against runtime errors that may be caused by a value changing unexpectedly.
you have to init the const attribute in the constructor with :
cat() : MAX_VALUE(-99999) {}
(which was declare as const int MAX_VALUE;)