views:

116

answers:

4

I understand that one benefit of having static member functions is not having to initialize a class to use them. It seems to me that another advantage of them might be not having direct access to the class's not-static stuff.

For example a common practice is if you know that a function will have arguments that are not to be changed, to simply mark these constant. e.g.:

bool My_Class::do_stuff(const int not_to_be_changed_1,
                        std::vector<int> const * const not_to_be_changed_2)
{
  //I can't change my int var, my vector pointer, or the ints inside it.
}

So is it valid to use static member functions to limit access. For example, lets say you have a function

void My_Class::print_error(const unsigned int error_no) {
  switch (error_no) {
    case 1:
      std::cout << "Bad read on..." << std::endl;
      break;
    //...
    default:
      break;
  }
}

Well here we're not going to be accessing any member variables of the class. So if I changed the function to:

static void My_Class::print_error(const unsigned int error_no) {
  switch (error_no) {
    case 1:
      std::cout << "Bad read on..." << std::endl;
      break;
    //...
    default:
      break;
  }
}

I'd now get an error, if I inadvertently tried to access one of my private var, etc. (unless I pass myself an instance of my class, which would be purposeful ^_^ !)

Is this a valid technique, similar to proactively making args that should not be changed constants?

What downsides might it have in terms of efficiency or use?

My chief reason for asking is that most of the "static" tutorials I read made no mention of using it in this way, so I was wondering if there was a good reason why not to, considering it seems like a useful tool.


Edit 1: A further logical justification of this use:

I have a function print_error,as outlined above. I could use a namespace:

namespace MY_SPACE {
   static void print_error(...) {
      ...
   } 

   class My_Class {
      ....
      void a(void)
   }
}

But this is a pain, because I now have to lengthen ALL of my var declarations, i.e.

MY_SPACE::My_Class class_1;

all to remove a function from my class, that essentially is a member of my class.

Of course there's multiple levels of access control for functions:

//can't change pointer to list directly
void My_Class::print_error(std::vector<int> const * error_code_list) {...}

//can't change pointer to list or list members directly
void My_Class::print_error(std::vector<int> const * const error_code_list) {...}

//can't change pointer to list or list members directly, access
//non-const member vars/functions
void My_Class::print_error(std::vector<int> const * const error_code_list) const {...}

//can't change pointer to list or list members directly, access
//non-static member vars/functions
static void My_Class::print_error(std::vector<int> const * const error_code_list) {...}

//can't change pointer to list or list members directly, access
//member vars/functions that are not BOTH static and const
static void My_Class::print_error(std::vector<int> const * const error_code_list) const {...}

Sure this is a bit atypical, but to lessening degrees so are using const functions and const variables. I've seen lots of examples where people could have used a const function, but didn't. Yet some people think its a good idea. I know a lot of beginning c++ programmers who wouldn't understand the implications of a const function or a static one. Likewise a lot would understand both.

So why are some people so adamantly against using this as an access control mechanism if the language/spec provides for it to be used as such, just as it does with const functions, etc.?

+5  A: 

Any member function should have access to the other members of the object. Why are you trying to protect yourself from yourself?

Static members are generally used sparingly, factory methods for example. You'll be creating a situation that makes the next person to work with your code go "WTF???"

Mark Ransom
Well say you have a member function where you absolutely don't need access to any of your other member functions/variables. Wouldn't it then be appropriate to limit that access using static? I know it sounds odd, but using the argument that you might need the access and some point when the code changes, could be used as an argument against constants in general.
Jason R. Mick
You frequently want to protect yourself from yourself. That's the reason const exists (or final, or readonly). These modifiers signal intent and keep you from using data in ways that are not intended.Also, for a function like 'print_error', I'd rather make it static and pass in an output stream then implicitly use an input stream bound to a particular object.
Outlaw Programmer
And as to the reaction by the next person viewing your code, if you properly document the code (your reason for making it static, as outlined above), your coworkers/colleagues should understand. Just like with const. When I see a const or a static function, I try to understand why the person made that distinction. Best case scenario is that they leave documentation of why.
Jason R. Mick
+3  A: 

Don't do this. Using static as an access-control mechanism is a barbaric abomination.

One reason not to do this is because it's odd. Maintenance programmers will have a hard time understanding your code because it's so odd. Maintainable code is good code. Everybody gets const methods. Nobody gets static-as-const. The best documentation for your code is the code itself. Self-documenting code is a goal you should aspire to. Not so that you don't have to write comments, but so that they won't have to read them. Because you know they're not going to anyway.

Another reason not to do this is because you never know what the future will bring. Your print_error method above does not need to access the class' state -- now. But I can see how it one day might need to. Suppose your class is a wrapper around a UDP socket. Sometime in the middle of the session, the other end slams the door. You want to know why. The last messages you sent or received might hold a clue. Shouldn't you dump it? You need state for that.

A false reason to do this is because it provides member access control. Yes it does this, but there are already mechanisms for this. Suppose you're writing a function that you want to be sure doesn't change the state of the object. For instance, print_error shouldn't change any of the object's state. So make the method const:

class MyClass
{
public:
  void print_error(const unsigned int error_no) const;
};

...

void MyClass::print_error(const unsigned int error_no) const
{
  // do stuff
}

print_error is a const method, meaning effectively that the this pointer is const. You can't change any non-mutable members, and you can't call any non-const methods. Isn't this really what you want?

John Dibling
+1 for 'barbaric abomination'
JoshD
But why does the spec allow `static` member functions at all then, if not for having it be reserved for helper functions that don't need to rely on other class members or use class variables (aside from a library of helper functions, perhaps...)?
Jason R. Mick
See my above description of varying levels of access in my new section entitled "Edit 1".
Jason R. Mick
@Jason: Because sometimes you *need* a class-level method, rather than an instance-level method. Two examples off the top of my head: callback functions and factory methods.
John Dibling
@Jason R. Mick: For performing actions that apply to *all* instances, or *no specific instance* where a specific instance is not necessary. Also often necessary when a lower level C API requires a callback function.
Clifford
A: 

It is certainly fair to say that global scope functions, static member functions, and friend functions aren't quite orthogonal to one another. To a certain extent, this is largely because they are intended to have somewhat different semantic meaning to the programmer, even though they produce similar output.

In particular, the only difference between a static member method and a friend function is that the namespaces are different, the static member has a namespace of ::className::methodName' and the friend function is just::friendFunctionName`. They both operate in the same way.

Well, actually there is one other difference, static methods can be accessed via pointer indirection, which can be usefull in the case of polymorphic classes.

So the question is, does the function belong as "part" of the class? if so, use a static method. if not, put the method in the global scope, and make it a friend if it might need access to the private member variables (or don't if it doesn't)

TokenMacGuy
A: 

Static member functions should be used when they are relevant to the class but do not operate on an instance of the class.

Examples include a class of utility methods, all of which are static because you never need an actual instance of the utility class itself.

Another example is a class that uses static helper functions, and those functions are useful enough for other functions outside the class.

Loadmaster
So based on your response its sounds like the example use case I originally asserted (a helper error printer function) would be a valid candidate for `static` in your mind.
Jason R. Mick
@Jason: Yes. Of course, I believe that practically *all* functions should be class members (static or not). Bare functions break object-oriented-ness (even though I realize that non-member template functions are useful as helper "glue" functions).
Loadmaster