Does it make sense to provide non-const reference getter
Asked Answered
L

9

7

Sometimes I need to expose some of the class members. For example in the following example class Mechanic may need direct access to Engine component. I have read many times that all fields should be accessed by mutator (accessor) methods because of several reasons. But is there any advantage when providing non-const reference getter:

class Car
{
    public:
        Engine & engine()
        {
           return m_engine;
        }

        //as a consequence you will also need to provide const version
        const Engine & engine() const
        {
           return m_engine;
        }

    private:
       Engine m_engine;
}

over simply making engine component public:

class Car
{
    public:
        Engine engine;
}

You can also replace public with protected if you don't like this example. In real life you have something simillar in Java when it comes to System.in or System.out. It looks like, to be fully compliant on what some people say, you would need to perform calls like System.getInstance().getOut().println("hello world"). I don't see any benefit except a lot of bureaucratic code in such cases.

Lavenialaver answered 6/11, 2010 at 15:56 Comment(6)
No close vote, but if the purpose of the question is to state a theory and then disagree with all answers contrary to that theory, then it's probably "subjective and argumentative". Whether your theory is right or wrong.Gerthagerti
@Steve Jessop: Don't be so zealous, sort questions by votes and you'll get a lot of inexact ones (question can not be subjective, the answer can be). Every answer is more or less subjective. In excuse of your your suspicions - I was on a trip and I haven't got opportunity to visit stackoverflow lately.Lavenialaver
that's why I'm uncertain. If someone is genuinely asking for reasons for something, I think that's fine even though there may be no definitive reason. If someone doesn't believe that there are any reasons, but asks for reasons anyway, I think that "usually leads to confrontation and argument". No serious harm done either way, but the latter isn't the purpose of the site AFAIK.Gerthagerti
Related: Why do people write private-field getters returning a non-const reference?Chapiter
Related: Breaking encapsulation by returning non-const references to membersChapiter
Here is a Regex for Visual Studio which may help find cases of methods returning non-const references: (?<!const\s+(?:\w+\s+)?|::)\b\w+(?:::\w+)*\s*(?:<[^<>]*>\s*)*&\s+\w+(?:::\w+)*\s*\( — May be not perfect, someone can suggest improvements!Chapiter
L
1

I have found reasonable point to provide such getter. It makes integration of your software easier (for example, when you want to translate interface into another language and bind ABIs).

Lavenialaver answered 13/11, 2010 at 12:38 Comment(0)
N
4

They can be useful when the value you are returning is actually on the heap.

template<class T> class Singleton
{
private:
    static T* m_pSingleton;

public:
    T& getSingleton() { assert(m_pSingleton); return(*m_pSingleton); };

}; // eo class Singleton
Noyes answered 6/11, 2010 at 15:59 Comment(3)
Definitely downvoting for the Singleton pattern.Oto
Ah, I remember the times when the Singleton pattern was all the rage... Heck, I even remember when PEEK and POKE was all the rage. :-)Twelfthtide
Yeah, arrays are evil, getters and setters are evil, singletons are evil, whole programming is evil. Best programmers are those who didn't write a piece of code. +1 because singletons are sometimes useful.Lavenialaver
C
3

Explicit getters and setters can be overly-bureaucratic; it depends on your situation.

The main cited reason for having getter and setter functions is that it isolates the clients of your class from potential changes in implementation in the future (for instance, consider what would happen if you decide to generate an Engine object on demand (rather than using a member variable), or decide to hide it behind a smart pointer, or some other container).

If your class if very simple (e.g. close to being a POD) and unlikely to change, then it may not be worth the faff of having to implement the getters and setters.

However, to answer your question, a non-const getter probably doesn't make much sense. Your getter prototype should be Engine & engine() const; otherwise you won't be able to call it on const Car objects.

Cat answered 6/11, 2010 at 16:2 Comment(2)
For better googling, this is called encapsulation.Estrada
I have fixed the example. There shall be two versions of engine() method: const and non-const. In my opinion sometimes it's convenient to expose members and draw back encapsulation.Lavenialaver
H
1

One advantage of providing a getter is that when and if you decide to change the way the getter works, the code that uses this class need not be recompiled. But if you have a public field and later decide to make a getter, all code should be recompiled. Other than that I don't see any serious practical reason to make your variable private. However note that this all holds if and only if you have to provide a way for outer users to get a reference to the Engine. If it is possible to design the software so that this need be eliminated at all, that would be better.

Hieroglyphic answered 6/11, 2010 at 16:0 Comment(1)
If you provide a field, and later change to a getter, client code doesn't just have to be recompiled, it has to be rewritten.Gerthagerti
A
1

As I happened to get educated on recently, getters and setters smell of bad design. But, if you want it that way, providing functions to get and set m_engine (Defined by you) rather than just exposing it (You have no intervention) means that you have a plug-in point for future changes.

Affidavit answered 6/11, 2010 at 17:16 Comment(8)
How can you implement, let's say, class Window with its width, height, and some other properties without getters nor setters? Aren't we going mad? Most real life object are like class Window; almost plain structures filled with some methods. I have met design with few accesors (although Window has got its GetWidth or GetSize methods) in the form of SFML library and because of that I was not able to extend its classes nicely.Lavenialaver
There were two points in my answer. The first is : Encapsulation is good. The second is, if you can't have the first, then getters and setters are good. The idea in the second scenario is to avoid code duplication that may happen in the future(Or right now) if you want to enforce some constraint on Windows width or height. On the first point, while setters can be excused a little, why do you need getters? Doesn't that mean that you'd rather have that bit of data the getter is exposing outside? If it is in the class, why let others tamper with it (Why even provide const getters)?Affidavit
In your question, what you should do is pass an object of Mechanic to a Car object so that the Car object can pass its Engine object to the Mechanic object. This way, you eliminate the getter and a Terrorist will not be able to access the engine of a Car.Affidavit
Check this (Which I asked a couple of weeks back) : #3933506 and this : idinews.com/quasiClass.pdf out. Should convert you :).Affidavit
@nakiya: Encapsulation is about hiding implementation details, not about getters, setters, whatever. You can have no getter nor setter and still brake encapsulation! On the other hand, if you will not provide all the necessary pieces of your class, then someone may be not able to extend this class nicely and this is also wrong.Lavenialaver
@nakiya: my intention is that Terrorist should also have an access to Engine component. It's loosely binded component.Lavenialaver
@doc: My point wasn't that getters and setters are bad always. it was just that I see the whole point in making one class do one specific thing well. Which means generally a class should not let others tamper with its inner data. If your class lets others do this, that means that it's data is not its own- which, you should be able to understand, is not very beautiful. And, on your second answer, Terrorist actually does have access to Engine is this universe with its laws. That does not mean its the best rules. Depending on whether you are a Terrorist or not.Affidavit
@nakiya: But I need to model this imperfect world and not to invent a perfect one.Lavenialaver
L
1

I have found reasonable point to provide such getter. It makes integration of your software easier (for example, when you want to translate interface into another language and bind ABIs).

Lavenialaver answered 13/11, 2010 at 12:38 Comment(0)
F
0

For me it makes sense here:

image(i,j) = 234;
Feinberg answered 6/11, 2010 at 16:0 Comment(0)
M
0

Instead of thinking about exposing private members of a class think more along the lines of calling methods on those classes. I read an interesting Java article, Why Getter and Setter Methods are Evil, which applies just as much to C++ as it does to Java.

Monarchy answered 6/11, 2010 at 16:3 Comment(2)
Yes I have read that and wrote the comment titled "Theory is just theory" :) My point is that code consists of operations and data, not only the code. Somehow you have to modify the data so the article is obviously wrong. The author doesn't see the big picture behind computing. He has stucked into some principles built on the top of it, called Object Oriented Programming. But OOP doesn't exist without procedural programming.Lavenialaver
@doc: If it is useless, why worry about what theory says in the first place? In regards to computer patterns, theory is not some abstract mathematical concept that some daydreamer conjures up (Read "Head first design patterns" on this). They are born out of necessity (Due to problems faced in practice). Your problem is one of them. So when someone says "Getters and setters are evil", it's not like saying "1 == 1".Affidavit
A
0

yes, it makes sense - for maintainability, validation, and consistency.

you may need to change many aspects of the class in the future, providing an accessor can help minimize breakage of client code.

you can enter all the validation logic you need here, to ensure that engine is a valid pointer, is not in an unusable state, etc.

finally, your code will be consistent: you won't have to open the header to know the member visibility - you just always know. this is also useful with templates.

Andrus answered 6/11, 2010 at 17:53 Comment(0)
E
0

In this case you would rather need a Car.fix(const Mechanic&) function which then gives the engine to the Mechanic, say: Engine.fix(const Mechanic&), as I suppose the state of the Engine will be modified.

The original idea of using classes was to tie together the data with its accessor functions. If you do setter or getter which merely returns an internal data, it means that your data is not tied together with its accessor functionality: your class is not complete.

You want only to expose new data which a class emits. Say Car.get_exhaust() and the Car does not have the exhaust, only produces it, when you ask so. ;)

Or Fire Riefle.fire() whereas no access for Riefle::Trigger will be fixed by the mechanic like so: Trigger.fix_by(Mechanic) and then the fix_by will call say Mechanic.add_working_hour(0.5). XD

Eclipse answered 14/11, 2012 at 18:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.