Using const getter-style functions in place of static data members - c++

A very simple thought that got me wondering: is there anything to be gained from using the following in a class:
static const int maximum_hp{10};
Rather than
int maximum_hp() const{return 10;};
...?
As far as I can see, the first way makes it easier to override the value of maximum_hp if needed in child classes (by declaring it virtual, of course); static data members cannot be modified, however. For constant primitive types, it seems, to me, to be a better way to go about it.

There is one thing which the static member gives you that the function does not: if the value is present in the class definition like you've shown, it can be used as a constant expression (such as an array bound or a template argument). In other words, this is legal:
std::array<int, Class::maximum_hp_static_memer> a;
while this is not:
std::array<int, c.maximum_hp_function()> a;

Related

Placing const, static and virtual before or after a method name?

Before I start, this is not a style opinion question. I want to know why and if I really have to place storage modifiers before the function. Philosophical discussion follows.
A very friendly C++ grammar policeman once taught me always to place modifiers to objects after the doodad to be modified. For example:
int const myint; // good
const int myint; // bad
The idea of this, and I quite like his or her reasoning, is that the modifier will then always modify the property before it. So when we declare a method the logical convention is this:
const int const fun(); // bad
int const fun() const; // good
So assuming that this is the way I do things, and without starting a debate on this all over again, why do I have to place storage modifiers (such as static) before the function? So a const and static function next to each other will confusingly look like this:
int fun1() const;
static int fun2();
Given that, conceptually, the static and const keywords in this context have categorically related roles (they both modify what the function can and cannot do, to be broad) shouldn't similar grammar rules apply to them? I want to be able to do this:
int fun1() const;
int fun2() static; // why doesn't this work?
The reason is that static is an entirely different sort of thing from const.
Specifically, static specifies a storage class, while const is a cv-qualifier (or just qualifier, depending on the standard you're looking at).
As such, the rules for the two are rather different. As you've already found, one of the rules is that a storage class specifier needs to be nearly the first item in the declaration, and that only one storage class can be specified in most declarations (the sole exception of which I'm aware: you can specify thread_local along with either static or extern).
There is a big difference between declaring a static or virtual function and func() const, in that the first defines how the the function interacts to the object it is a member of, and the second form defines what it is allowed to do TO the object it is a member of.
And, yes, it's slightly confusing that one comes after the function prototype, and the other is before. I think that is because it would be even more confiusing if const char * const x = "abc" means something different than const char * const func() { return "abc"; } - and it is a good idea to keep the number of reserved words t a minimum in the language, so adding a "constfunc" or something like that to the reserved words was deemed a bad idea. By placing it after the () in the function declaration, it avoids confusion and allows the same word to be used for another purpose.
const does not actually modify the function, but the type of the implicit this pointer. All functions are immutable as far as the C++ type system is concerned (C++ does not provide any language support for self-modifying code).
For that reason it doesn't make sense to compare its position to either the return type or function modifiers.

Why not static const references on class member variables?

I have a question about static references on class members in C++. It is easy to create a static const member which is a pointer on a non-static member of the same class; like this:
class A {
public:
int x;
private:
static int A::* const ptr_on_x;
};
int A::* const ptr_on_x = &A::x;
Now, I cannot figure out why I cannot write something like that, i.e. make a static const member which is a reference on a non-static member of the same class:
//won't compile
class B {
public:
int x;
private:
static int B::& const ptr_on_x;
};
int B::& const ptr_on_x = B::x;
From the various posts in SO about différences between pointers and references, I don't find any clue. On the contrary, I even read that "references are kind of aliases". So what do I misundertand?
So is it possible to define some variable aliases inside the same class? I admit that with a simple class it doesn't seem very useful; it is a question about the langage itself.
Also I don't know C++0x very much, so does C++0x offers a solution for this?
EDIT
The comment of MarcinŁoś gives me another idea. You can take a function reference, so can I create a class member which is a reference on a class method?
Simply because there is no such type as a reference-to-member, only a pointer-to-member.
From the various posts in SO about différences between pointers and references, I don't find any clue.
A pointer-to-member has little to do with a pointer apart from its (slightly misleading) name, and the fact that, like a pointer, it refers to something else. There was never considered to be a compelling reason to add an analogous type that looked more like a reference.
So is it possible to define some variable aliases inside the same class?
No, there's no sensible way to do that.
Also I don't know C++0x very much, so does C++0x offers a solution for this?
No.
I think the main confusion is that the pointer is simply an offset pointer (it knows where the member is located in relation to the struct), not an absolute pointer, while a reference is always absolute, hence you cannot do the same.

Is it better to replace constants by template parameters?

Is it better to do:
const int MY_CONST = 20; // global constant in the program
class A {
// uses MY_CONST all over the class implementation and definition
}
or this?
const int MY_CONST = 20; // global constant in the program
template<int my_const>
class A {
//uses my_const only and never MY_CONST
};
//A<MY_CONST> used later in the program
Is one of these pattern better than the other? why?
thanks
Unless that global constant is used elsewhere outside of the class I would use neither of those approaches and make the constant a member of A:
class A {
public:
static const int MY_CONST = 20;
};
const int A::MY_CONST; // Possibly need definition also
And then use A::MY_CONST in your code.
The only time I would use a template is when you need to change the value depending on the instance for some reason.
template <int I>
class A
{
public:
static const int MY_CONST = I;
};
template <int I>
const int A<I>::MY_CONST; // Definition
Then create instances like so:
A<1> a1;
A<2> a2;
The second solution is sensible if it makes sense to instantiate e.g. A<MY_CONST + 1>, or A<0>, or any other value than MY_CONST. If, however, A is strictly designed to be used with the one value, then you don't gain anything from that. In that respect the first solution gives you everything you need.
One way to look at it is that you're introducing a dependency to A (only on a number, not on anything with behavior, but still that's a kind of dependency), and the question is whether to inject that dependency via a template parameter, or have the class pull in the dependency via a named const object.
I can see the template being useful for testing the class A -- you want to write the class to work with any value, so that you can change the value in future with confidence that you won't immediately get test failures and have to fix the bugs.
So, you could write the template and test it with lots of different values, even though no "real" program will use more than one instantiation of the template.
Obviously there are other ways to write a class whose behavior depends on an integer value, and test it. For example you could use a macro and have the test harness compile the code multiple times, or you could make MY_CONST an extern value and link the code against different object files containing different values, or you could make A store the value as a data member (even a static data member).
Which ones work for you depends how the class is going to use the value, but since a template parameter is an integer constant expression it's good for most uses that the const int is good for. You can't take a template parameter's address, is the only thing that immediately springs to mind.
I would always remove the global variable. Let's distinguish 2 cases, MY_CONST is either
an implementation detail in which case I would prefer to make it a private constant
class A
{
private:
static int const MY_CONST = 20;
};
or part of the class interface in which case I would prefer to make it a template parameter and provide it as a public member
template<int N>
class A
{
public:
static int const MY_CONST = N;
};
This way, users can not only read but also "write" (at compile-time) to MY_CONST. If users will not want to specify anything but a default value for N, you could provide a default template argument, or give a simple typedef
typedef A<20> DefaultA;

static const Member Value vs. Member enum : Which Method is Better & Why?

If you want to associate some constant value with a class, here are two ways to accomplish the same goal:
class Foo
{
public:
static const size_t Life = 42;
};
class Bar
{
public:
enum {Life = 42};
};
Syntactically and semantically they appear to be identical from the client's point of view:
size_t fooLife = Foo::Life;
size_t barLife = Bar::Life;
Is there any reason other than just pure style concerns why one would be preferable to another?
The enum hack used to be necessary because many compilers didn't support in-place initialization of the value. Since this is no longer an issue, go for the other option. Modern compilers are also capable of optimizing this constant so that no storage space is required for it.
The only reason for not using the static const variant is if you want to forbid taking the address of the value: you can't take an address of an enum value while you can take the address of a constant (and this would prompt the compiler to reserve space for the value after all, but only if its address is really taken).
Additionally, the taking of the address will yield a link-time error unless the constant is explicitly defined as well. Notice that it can still be initialized at the site of declaration:
struct foo {
static int const bar = 42; // Declaration, initialization.
};
int const foo::bar; // Definition.
They're not identical:
size_t *pLife1 = &Foo::Life;
size_t *pLife2 = &Bar::Life;
One difference is that the enum defines a type that can be used as a method parameter, for example, to get better type checking. Both are treated as compile time constants by the compiler, so they should generate identical code.
static const values are treated as r-values just like enum in 99% of code you'll see. Constant r-values never have memory generated for them. The advantage enum constants is they can't become l-values in that other 1%. The static const values are type safe and allow for floats, c-strings, etc.
The compiler will make Foo::Life an l-value if it has memory associated with it. The usual way to do that is to take its address. e.g. &Foo::Life;
Here is a subtle example where GCC will use the address:
int foo = rand()? Foo::Life: Foo::Everthing;
The compiler generated code uses the addresses of Life and Everything. Worse, this only produces a linker error about the missing addresses for Foo::Life and Foo::Everything. This behavior is completely standard conforming, though obviously undesirable. There are other compiler specific ways that this can happen, and all standard conforming.
Once you have a conforming c++11 compiler the correct code will be
class Foo {
public:
constexpr size_t Life = 42;
};
This is guaranteed to always be an l-value and it's type-safe, the best of both worlds.
Well, if needed, you can take the address of a static const Member Value. You've have to declare a separate member variable of enum type to take the address of it.
Another third solution?
One subtle difference is that the enum must be defined in the header, and visible for all. When you are avoiding dependencies, this is a pain. For example, in a PImpl, adding an enum is somewhat counter-productive:
// MyPImpl.hpp
class MyImpl ;
class MyPimpl
{
public :
enum { Life = 42 } ;
private :
MyImpl * myImpl ;
}
Another third solution would be a variation on the "const static" alternative proposed in the question: Declaring the variable in the header, but defining it in the source:
// MyPImpl.hpp
class MyImpl ;
class MyPimpl
{
public :
static const int Life ;
private :
MyImpl * myImpl ;
}
.
// MyPImpl.cpp
const int MyPImpl::Life = 42 ;
Note that the value of MyPImpl::Life is hidden from the user of MyPImpl (who includes MyPImpl.hpp).
This will enable the MyPimpl author to change the value of "Life" as needed, without needing the MyPImpl user to recompile, as is the overall aim of the PImpl.

What does the const operator mean when used with a method in C++?

Given a declaration like this:
class A {
public:
void Foo() const;
};
What does it mean?
Google turns up this:
Member functions should be declared with the const keyword after them if they can operate on a const (this) object. If the function is not declared const, in can not be applied to a const object, and the compiler will give an error message.
But I find that somewhat confusing; can anyone out there put it in better terms?
Thanks.
Consider a variation of your class A.
class A {
public:
void Foo() const;
void Moo();
private:
int m_nState; // Could add mutable keyword if desired
int GetState() const { return m_nState; }
void SetState(int val) { m_nState = val; }
};
const A *A1 = new A();
A *A2 = new A();
A1->Foo(); // OK
A2->Foo(); // OK
A1->Moo(); // Error - Not allowed to call non-const function on const object instance
A2->Moo(); // OK
The const keyword on a function declaration indicates to the compiler that the function is contractually obligated not to modify the state of A. Thus you are unable to call non-const functions within A::Foo nor change the value of member variables.
To illustrate, Foo() may not invoke A::SetState as it is declared non-const, A::GetState however is ok because it is explicitly declared const. The member m_nState may not be changed either unless declared with the keyword mutable.
One example of this usage of const is for 'getter' functions to obtain the value of member variables.
#1800 Information: I forgot about mutable!
The mutable keyword instructs the compiler to accept modifications to the member variable which would otherwise cause a compiler error. It is used when the function needs to modify state but the object is considered logically consistent (constant) regardless of the modification.
This is not an answer, just a side comment. It is highly recommended to declare variables and constants const as much as possible.
This communicates your intent to users of your class (even/especially yourself).
The compiler will keep you honest to those intentions. -- i.e., it's like compiler checked documentation.
By definition, this prevents state changes you weren't expecting and can, possibly, allow you to make reasonable assumptions while in your methods.
const has a funny way of propagating through your code. Thus, it's a really good idea to start using const as early and as often as possible. Deciding to start const-ifying your code late in the game can be painful (easy, but annoying).
If you're using a language with static, compile time checks it's a great idea to make as much use of them as possible... it's just another kind of testing really.
Functions with const qualifier are not allowed to modify any member variables. For example:
class A
{
int x;
mutable int y;
void f() const
{
x = 1; // error
y = 1; // ok because y is mutable
}
};
C++ objects can be declared to be const:
const A obj = new A();
When an object is const, the only member functions that can be called on that object are functions declared to be const. Making an object const can be interpreted as making the object readonly. A const object cannot be changed, i.e. no data members of the object can be changed. Declaring a member function const means that the function is not allowed to make any changes to the data members of the object.
Two suggested best practices from experience:
(1) Declare const functions whenever possible. At first, I found this to be just extra work, but then I started passing my objects to functions with signatures like f(const Object& o), and suddenly the compiler barfed on a line in f such as o.GetAValue(), because I hadn't marked GetAValue as a const function. This can surprise you especially when you subclass something and don't mark your version of the virtual methods as const - in that case the compile could fail on some function you've never heard of before that was written for the base class.
(2) Avoid mutable variables when it's practical. A tempting trap can be to allow read operations to alter state, such as if you're building a "smart" object that does lazy or asynchronous i/o operations. If you can manage this with only one small mutable variable (like a bool), then, in my experience, this makes sense. However, if you find yourself marking every member variable as mutable in order to keep some operations const, you're defeating the purpose of the const keyword. What can go wrong is that a function which thinks it's not altering your class (since it only calls const methods) my invoke a bug in your code, and it could take a lot of effort to even realize this bug is in your class, since the other coder (rightly) assumes your data is const because he or she is only calling const methods.
const has a funny way of propagating through your code. Thus, it's a really good idea to start using const as early and as often as possible. Deciding to start const-ifying your code late in the game can be painful (easy, but annoying).
Additionally, you will easily run into problems if methods that should be const aren't! This will creep through the code as well, and make it worse and worse.
that will cause the method to not be able to alter any member variables of the object