8

Here is my situation (a simple example).

Say I have a class called HiddenData
Then I have another class called StoreHiddenData
And finaly a class called OperateHiddenData

Here's the thing, my class called HiddenData has private members that I don't want to be visible to the rest of the world, but I still need classes to be able to operate on private members of this HiddenData class (StoreHiddenData and OperateHiddenData for example). I would like to be able to pass this object around to different classes that do different things on it.

Another thing I was thinking of is to create a form of handle to these HiddenData objects, but I can't think of a way to use handles without using friend classes again (as to give the other classes access to a table that contains what the handles point to, without exposing it to the rest of the world as well).

I was reading this question on this site just a while ago as I was researching the use of friend classes, and it has me thinking if using friends is the best way to go.

If anyone has any suggestions for how to accomplish this task without the use of friend classes in C++, or if the use of friend classes is an OK OOP practice, please provide me with any suggestions. Thanks.

EDIT: I figure I should add a little bit more information about my problem. For one thing, I am trying to create an API that consists of several classes that hide their functionality from the outside and only allow public functions to be accessed. On the inside I have data structures (or classes, doesn't really matter), that need to be passed around to these different classes with public functions. I don't want the outside to have access to anything inside these data structures other than being able to pass them around to functions of the API. I kind of think of it like the Windows API, where you pass around Handles to API functions, but you can't actually dissect the handles in your own code. Well I would like to do something very similar, but while remaining object oriented, and NOT passing these private data structures around by value because they will be BIG. Thanks again.

6
  • I don't see why not - that's what friend classes are for. I mainly work with Java, and there are times I wish I could do that. Commented Jan 29, 2012 at 18:37
  • 2
    To add to @MikeBaranczak - there are several examples of good use of friend in C++. For example, the Iterator design pattern can use friend to access private members so that the aggregate (the thing being iterated over) doesn't have to expose methods for the sole purpose of iteration. It lets you keep iteration methods in the iterator and data structure maintenance methods in the data structure. Using friend to accomplish similar goals is probably a good use of the language constructs of C++.
    – Thomas Owens
    Commented Jan 29, 2012 at 19:13
  • 1
    Ok, here's the deal: Every tool has a variety of tricks available. Friend classes do indeed make private members available to other classes. However, to answer your question, I need to learn more about the nature of the problem. Can you broadly describe the scenario and why you think encapsulation of the form described above is appropriate? Commented Jan 29, 2012 at 23:16
  • @StephenGross: I don't really know how else to explain it. I have an object that I only want a few functions of to be exposed to the rest of the program, except for the few classes that have functions that take that object as a parameter and operate on private members. I want these objects to be passed around anywhere in the program, and have a limited number of functions available, but for the most part they hold data I want only to be accessible to a few components of the program. Commented Jan 30, 2012 at 1:34
  • 1
    @JAKE6459: If you have few functions that you want to expose to everyone, put those functions into an interface (abstract virtual no-implementation base class) and pass that interface type around your whole app. Then have your "special" code use the object directly through well-defined public class interface.
    – DXM
    Commented Jan 30, 2012 at 3:29

5 Answers 5

11

I would be extremely cautious about the use of friends. Although friends, have their time and place, most of the time when people use them, it's only as a convenient way of breaking encapsulation, which makes the code easy to write and deliver v1.0 but as the number of classes that operates on your HiddenData increases and as the average size of those classes increases, it will become a nightmare to read and modify.

I've used friends a few times, but only when alternatives would've been even uglier/harder to maintain. Iterators which are associated with a specific collection is definitely a good example of using friends.

Another example is implementations of finite state machines(FSM), where each state is represented by a separate class. Here your FSM is your real class, the states are just a way of splitting up logic into manageable units, but generally the data still belongs to FSM.

Bottom line, I would lean towards friends if second class is extremely small and won't be extended with more and more functionality with each release. Also the placement of the two classes should be as close as possible to one another. In case of STL's iterators, those classes are defined right inside their own container classes. Don't get any closer than that.

There are several ways of implementing your scenario while not having to break encapsulation by using friends. Here's only few of many alternatives:

  1. Have HiddenData be truly hidden. Don't freely give out reference to it. Instead have another adapter/view/decorator (whatever you want to call it) class between the data and the public. This other class would ensure that only public operations are allowed. Then your special manipulator classes would access normal public interface of HiddenData directly.

  2. Take a look at Visitor Pattern. It might be exactly what you need. It give you the ability to add functionality to a class without actually touching the class itself. So to implement another special manipulator which has access to internal data, you would create a new visitor class and give a reference to a single Accept() method of the HiddenData.

10
  • 9
    friend don't break encapsulation for a very simple reason: a class cannot become friend of another without the other wants it. The friends, together, are just another bigger "capsule". Commented Jan 30, 2012 at 8:40
  • 1
    @EmilioGaravaglia: friend is a way to break encapsulation "locally". If I write an application which contains 20 classes and all data is private, but these class all happen to be friends with each other. Would you consider encapsulation to be preserved? Maybe all data is private, but I can tell you right now that app will be a royal PITA to maintain, just like one which has no encapsulation. So if you have a larger app with 500 classes, but 20 of them happen to be friends, as those 20 grow and morph and get touched by multiple developers, you will experience exactly the same pains
    – DXM
    Commented Jan 30, 2012 at 9:11
  • @DXM: "local" encapsulation is an artefact of the fact, that in OOP class triples as a data type, unit of code reuse and unit of encapsulation, but it does not always make sense. When it does not, you define the unit of encapsulation with friends. If you have 20 classes that are mutual friends, you have the same problem as if you had one class with the same amount of code. It is simply bad design and does not say anything about friend being evil.
    – Jan Hudec
    Commented Jan 30, 2012 at 11:20
  • 1
    @DXM: C++ is a "pragmatic language". And "pragmatism" is not for Talibans. If you have 20 classes all each other friend and you know what have you done, your mess it's up to you. But you are always granted that I -using your classes with my own classes- will never be able to mess up your "private parts". Whatever mess they can be / have themseves. The "encapsulation", in a pragmatic language, is no more than that. Be sure nothing external to a context can mess up things inside. How wide a context should be, and how many things should contain is a matter of design, not of keywords. Commented Jan 30, 2012 at 18:28
  • 1
    As an aside, iterators in C++ are not actually members of their container anymore for quite some time now. The reason is simple: Not all the containers template-arguments are relevant to the iterator used, thus the earlier design lead to needless restrictions and duplication. Commented Oct 7, 2015 at 14:27
10

C++ friends exist just for that. Every other surrogate will simply mimic the same concept.

  • There are thing that are for everyone,
  • Things for you only, (eventually inherited from your children)
  • Things shared by you with a well define and limited set of people.

Those "people" are called "friend". Eliminating that concept will require those things to become public, or to become private, but with public accessors to be managed. You must also expect anyone to be capable of doing things with them out of your control.

0

No, you should not use friend classes. Expose public API that so that your clients (at this point, you, via StoreHiddenData and OperateHiddenData) are able to modify the contents of Hidden Data with the use of an API. As a last resort, use getters and setters.Make sure you design your public interface to be cohesive, don't just expose functionality to be able to write fast code.

But before you do anything, read Effective C++ by Scott Meyers. It will answer a lot of your questions, and it's always useful as a reference book.

0

I think this is a difficult question, because it can be a matter of preference. How many friends is too many?

As a single anecdote, this is done in the wild, in large professional software codebases.

Unreal Engine

Unreal Engine, a rather large game engine written in C++ makes use of friend classes to allow protected member access for related logic.

In one such case a class that controls movement (UChaosVehicleMovementComponent ) is a friend of a manager class that facilitates physics calculations for instances of UChaosVehicleMovementComponent

This allows access to protected member functions from the manager class.

class CHAOSVEHICLES_API UChaosVehicleMovementComponent : public UPawnMovementComponent
{
    friend class FChaosVehicleManager;
// ...
protected:
    FVehicleState VehicleState; 

}

This allows the manager class to access an array of UChaosVehicleMovementComponent and call protected member functions (VehicleState)

if (Vehicles[i]->VehicleState.bSleeping)
{
    SleepingCount++;
}

for the curious: Engine\Plugins\Experimental\ChaosVehiclesPlugin\Source\ChaosVehicles\Public\ChaosVehicleMovementComponent.h

0

You use "friend" classes if you have two or more classes that are closely connected.

You organise things in your code so that you have individual things that are separate, and often a "class" is a reasonable boundary to keep things separate, so you can change the implementation or private items of the class without changing anything else.

But sometimes you have classes that need to work very closely together. In a single class, all your methods have access to everything in the class. And if you make one change, say to a field of the class, you may have to change other things in the class, and that is the expected thing. But sometimes you have two classes where the same is true. You expect to change them together. They cannot stand on their own feet, they need each other. That's when you make one class a "friend" of the other, and that is a situation where it is absolutely fine and the right thing to do.

(Swift has an interesting feature - "fileprivate" items. They are like private items, but can be accessed by any code in the same source file. And if you have two classes that work together closely, you'd want them in one file, right? And "private" items cannot be accessed. )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.