I always seem to struggle with the decision of whether a value in a class which should be static
and const
should be public or private with a static public method for access.
class DeepThought
{
public:
static const int TheAnswer = 42;
};
versus:
class 开发者_Python百科DeepThought
{
public:
static int GetTheAnswer() { return TheAnswer; }
private:
static const int TheAnswer = 42;
};
I want to do it the first way, but somewhere deep inside me feels like it breaks encapsulation even though its a constant value. The second way just seems like it doesn't really add anything to the table though and needlessly clutters up the code.
So I ask, is there anything fundamentally wrong with either choice and if so, what?
In a purely theoretical sense, the second option is the more correct. In the practical sense, I agree with you - wrapping the constant value with a getter function is useless and will be removed by the compiler anyway.
In my experience, sometimes the simpler approach is better, even if it violates OOP somewhat.
And a final note - we used to use enums for this:
enum CONSTS
{
TheAnswer = 42,
};
They aren't semantically equivalent. Prefer the first, because it yields an integral constant expression which can be used in array bounds, nontype template arguments, case expressions, etc.
int a[DeepThought::TheAnswer]; // ok
int b[DeepThought::GetTheAnswer()]; // broken
You should think about why the OOP "ideology" says don't expose variables, only getters. The usual argument is because you might, at some point in the future, need to make access to that variable do something more complicated. But the odds of this are small to begin with, and become even smaller when you're talking about a constant.
I would go ahead and expose the constant as a constant. But then I would also usually go ahead and expose variables when there is no current need for a getter. The Python crew would call this an application of the You Aren't Gonna Need It principle.
There is the obvious:
class DeepThought
{
public:
static int GetTheAnswer() { return 42; }
};
You may as well use the first. Consider- what logic are you going to put in to GetTheAnswer()
? You can't change it's signature or the fact that it's static without breaking it's interface considerations. This means that unless you're going to start making non-constant global variables, which would be Extremely Bad™, there's nothing you might put in GetTheAnswer()
that you can't put in the constexpr which TheAnswer
is assigned to.
Moreover, there are limits with what you can do with GetTheAnswer()
, for example, in the first you could take the address of the constant and with GetTheAnswer()
, you can't, even though it's pretty reasonable that you should be able to.
these constants like this are basically hidden singleton pattern. There is only one instance of the constants available. This will be the normal evolution of such code:
class DeepThought {
public:
static const int i=10;
void f() { std::cout << i; }
};
Then you'll want to change the variable to change on runtime, it'll become like this:
class Singleton {
static Singleton &get() { static Singleton s; return s; }
int get_i() const { return i; }
};
class DeepThought {
public:
void f() { std::cout << Singleton::get().get_i(); }
};
Then at some point you'll want more than one instance of the constant and it'll become like this:
struct Data
{
int i;
};
class DeepThought {
public:
DeepThought(Data &d) : d(d) { }
void f() { std::cout << d.i; }
private:
Data &d;
};
int main() { Data d; DeepThought dt(d); dt.f(); }
During the evolution of the code, it'll change quite much and if you have large amount of code like that, doing the changes could take large amount of effort.
精彩评论