views:

74

answers:

5

Well, I'm not sure about this one.

I have a class like

    class Object
    {
        int internalValue ;
        struct SomeStructType
        {
            int superInternalValue ;
        } someStruct ;

    public:
        int getInternalValue()
        {
            return internalValue ;
        }

        int getSuperInternalValue()
        {
            return someStruct.superInternalValue ;
        }

        void printThatInternalValue()
        {
            // Its seems pretty clear we should just access
            // the private value directly and not use the public getter
            printf( "%d", internalValue ) ;
        }

        void printThatSuperInternalValue()
        {
            // Now here the access pattern is getting more complicated.
            // Shouldn't we just call the public access function
            // getSuperInternalValue() instead, even though we are inside the class?
            printf( "%d", someStruct.superInternalValue ) ;
        }
    } ;

So for the class's INTERNAL operations, it CAN use someStruct.superInternalValue directly, but it seems cleaner to use the class's public getter function getSuperInternalValue() instead.

The only drawback I can see is if you tried to modify superInternalValue using the getter would give you a copy, which is clearly not what you want in that case. But for reading access, should the public getter function be used internally inside a class?

+2  A: 

If the accessor cannot be overridden, a class can use its private members directly. Otherwise, it should use the accessor, so that if it is overridden, the class will continue to operate correctly.

erickson
The question isn't just "can it" use its private members, it's "should it". In this example (assuming it's C++), the getter cannot be overridden, because it is not virtual.
Steve Jessop
I would think this is backwards. If an accessor can be overridden the base class will behave differently which could come as an unexpected surprise to the developer.
Spencer Ruport
@Spencer that's why you generally shouldn't allow things to be overridden. If overriding would break the base class, don't allow it. If you cede that control, the developer who extends your class gets an even bigger surprise when overriding an accessor has no effect. Accessors are there for the object to use, not so that other classes can break its encapsulation and tinker with its state.
erickson
Right hence my confusion with your answer. If the base class does need to manipulate internal data before storing it then it should do so using some sub or function that cannot be overridden, if the base class doesn't need to manipulate internal data there's no reason not to assign it directly to the private variable. Right?
Spencer Ruport
What you are saying makes sense for assignment to member variables. My answer is geared more toward reading members—does the class use the accessor, or directly access the member?
erickson
@Spencer: depends whether you think the accessor is a way of getting at something that's "really" a member, or the member as the implementation backing up the accessor. Since the accessor is the public part of the interface, I say primarily the latter. If a subclass is permitted to override, and wants to implement the accessor differently, perhaps calculating the value somehow, then that might be a reasonable use of inheritance. An example would be if the getter is part of a Template Method pattern (you'd expect that to be abstract, but the base could provide a default).
Steve Jessop
A: 

I would suggest that, if in doubt, use the accessor.

While an accessor may, originally, act as a simple wrapper that does nothing more than gets the value of the private member, a future modification to the accessor may change this behaviour such that any other method accessing the member directly no longer has a consistent view of its value.

Dancrumb
A: 

The only other reason I can see to use the public accessor is just in case the accessor does something other then just returning the value saved in the variable; for example, returning a default value if the variable in memory is invalid for some reason.

In the example you gave, either way is fine, and accessing the variable directly means less code for your program to go through to get the value to show.

David Parvin
A: 

It all depends. I don't think that in general you should use getter inside class. For example,

int MyClass::getFoo() const
{
   int retval(0);
   m_myMutex.lock();
   retval = m_foo;
   m_myMutex.unlock();
   return retval;
}

You won't probably use such a getter inside MyClass.

a1ex07
A: 

I'd say at least 90% of the time that questions like this arise, it's a good sign that you're probably trying to put too much functionality into one class. If someStruct::SuperInternalValue should really be accessed via getSuperInternalValue, then chances are pretty good that it should be part of someStruct instead of being part of Object.

Likewise, if you need to print out a someStruct, then Object should just use a member function (or overloaded operator in a language that supports it) to print out a someStruct object (as a whole). As you've written it, Object::printThatSuperInternalValue knows everything about someStruct and superInternalValue.

Despite source code containing "class" and "Object", what you really have is code in Object acting on dumb data in someStruct. In other words, what you have isn't really OO at all -- it's simple procedural code with a data structure. That's not necessarily all bad, but based on the encapsulation tag, I think it's a fair guess that it's probably not what you really want.

class Object { 
    int internalValue;
public:
    class someStruct { 
        int superInternalValue;
    public:
        someStruct(int v) : superInternalValue(v) {}
        someStruct &operator=(someStruct const &n) { 
             superInternalValue = n.superInternalValue;
             return *this; 
        }
        friend ostream &operator<<(ostream &os, someStruct const &s) {
            return os << s.superInternalValue;
        }
    };
    friend ostream &operator<<(ostream &os, Object const &o) { 
        return os << internalValue;
    }
};

This way we've defined someStruct in terms of an interface (we can create one from an int, assign them and print them) and Object doesn't need to deal with/touch superInternalValue at all. The important part isn't that we've stopped Object from playing with the internals of somestruct, but that we've made someStruct intelligent enough that Object can now ignore all the gory details of how someStruct is implemented.

Jerry Coffin
Well, its mostly to do with MSFT type structs. You know, these enormous structs like http://msdn.microsoft.com/en-us/library/aa930622.aspx need to be stored, but only .biWidth and .biHeight need to be exposed, for example.
bobobobo