views:

114

answers:

2

I have a set of functions that work on a file. Originally I made it into a class, with the only private member being a static const std::string which was the name of the file. The user used these functions by creating an object and calling functions from it. However, I think I'm going to switch to using a namespace, since it's just a set of functions and makes more sense. The only problem is that I still would like to keep that constant string. Would doing something along these lines be fine?

namespace FileHandler {
    // Functions to do stuff with file
    const std::string FILE_NAME;
}

I have a separate implementation file for the namespace, but I'm wondering if the loss of encapsulation from having the file name be a private member in a class is worth using the namespace instead.

+3  A: 

You can do similar things but they will have different semantics.

In a class, a static variable is a declaration, not a definition, it still requires a definition outside of the class; a variable declaration in a namespace is a definition unless you mark in as extern and don't provide an initializer.

In your case it doesn't make too much difference as const variables have internal linkage by default so you can have multiple definitions in a program (one per translation unit) without problems.

E.g.

class Test
{
    static const std::string FILE_NAME;
};

is (in some ways) equivalent to:

namespace Test
{
    extern const std::string FILE_NAME;
}

If you did this, you would be declaring FILE_NAME as an empty string. You couldn't redeclare it elsewhere in the same translation unit.

namespace Test
{
    const std::string FILE_NAME;
}

You could, though, do this.

namespace Test
{
    const std::string FILE_NAME = "myfile.txt";
}

Each translation unit would have its own version of Test::FILE_NAME but they would all be consistent.

Charles Bailey
Thanks for the info. The reason I'm not including the string's definition in the header file for the namespace is because it isn't necessary for the user to know, which is why I define it in the implementation file along with the functions in the namespace.
Anonymous
In that case you can do `extern const std::string blah;` in the header file and `const std::string ns::blah = "whatever";` in the source file.
Charles Bailey
Am I missing something - why even declare this file name in the header, if it was previously private and the user doesn't need to know it? Is it used in some inline code in the header, or a default function parameter, or some such? If not, just move it entirely into the implementation file.
Steve Jessop
@Steve Jessop: Probably not! If - as is usually the case - all of the 'class' implementation is/was in the same source file then the string could just be in an anonymous namespace in that source file.
Charles Bailey
+1  A: 

I do not see the problem that led you to switch from using a class to using a namespace. If every function is acting on the file whose name is stored in FILE_NAME, then the file seems like a perfectly valid part of an object's state. Switching from that to what amounts to a global variable is a strong code smell. What happens when you want to perform operations on two files at once? What if you want to support different file types? It is much easier to address these questions with an object-oriented approach that avoids global state.

If you really want to switch to using "a set of functions", then you may want to consider a more functional approach in which each function takes the name of the file (or a file pointer) as a parameter. That way, the functions have no need to access global state.

Brett Daniel