Say I have a class with a private data member n and a public get_n() function.
When overloading the output operator for example, I can either use get_n() or make it a friend and use n.
Is there a ‘best’ choice? And if so, why?
Or is the difference going to be optimized away?
Thanks.
Say I have a class with a private data member n and a public
Share
You’ve already gotten a lot of somewhat-conflicting answers, so what you undoubtedly need is one more that contradicts nearly all of them.
From an efficiency viewpoint, it’s unlikely to make any difference. A function that just returns a value will undoubtedly be generated inline unless you specifically prohibit that from happening by turning off all optimization.
That leaves only a question of what’s preferable from a design viewpoint. At least IMO, it’s usually preferable to not have a
get_nin the first place. Once you remove that design problem, the question you asked just disappears: since there is noget_nto start with, you can’t write other code to depend upon it.That does still leave a small question of how you should do things though. This (of course) leads to more questions. In particular, what sort of thing does
nrepresent? I realize you’re probably giving a hypothetical example, but a good design (in this case) depends on knowing a little more about whatnis and how it’s used, as well as the type of whichnis a member, and how it is intended to be used as well.If
nis a member of a leaf class, from which you expect no derivation, then you should probably use a friend function that writesnout directly:Simple, straightforward, and effective.
If, however,
nis a member of something you expect to use (or be used) as a base class, then you usually want to use a “virtual virtual” function:Note, however, that this assumes you’re interested in writing out an entire object, and it just happens that at least in the current implementation, that means writing out the value of
n.As to why you should do things this way, there are a few simple principles I think should be followed:
get_n(and, as often as not, publicset_nas well) may be required for JavaBeans (for one example) but is still a really bad idea, and shows a gross misunderstanding of object orientation or encapsulation, not to mention producing downright ugly code.get_nfrequently means you end up with client code that does a read/modify/write cycle, with the object acting as dumb data container. It’s generally preferable to convert that to a single operation in which the client code describes the desired result, and the object itself does the read/modify/write to achieve that result.get_nis nearly always a good thing in itself, independent of its being good for encapsulation.Since others have commented about
friendfunctions, I’ll add my two cents worth on that subject as well. It’s fairly frequent to hear comments to the effect that “friend should be avoided because it breaks encapsulation.”I must vehemently disagree, and further believe that anybody who thinks that still has some work to do in learning to think like a programmer. A programmer must think in terms of abstractions, and then implement those abstractions as reasonably as possible in the real world.
If an object supports input and/or output, then the input and output are parts of that object’s interface, and whatever implements that interface is part of the object. The only other possibility is that the type of object does not support input and/or output.
The point here is pretty simple: at least to support the normal conventions, C++ inserters and extractors must be written as free (non-member) functions. Despite this, insertion and extraction are just as much a part of the class’ interface as any other operations, and (therefore) the inserter/extractor are just as much a part of the class (as an abstraction) as anything else is.
I’d note for the record that this is part of why I prefer to implement the friend functions involved inside the class, as I’ve shown them above. From a logical viewpoint, they’re part of the class, so making them look like part of the class is a good thing.
I’ll repeat one last time for emphasis: Giving them access to class internals can’t possibly break encapsulation, because in reality they’re parts of the class — and C++’s strange requirement that they be implemented as free functions does not change that fact by one, single, solitary iota.