Book a Demo

Author Topic: Question about friends  (Read 12061 times)

EricP

  • EA User
  • **
  • Posts: 122
  • Karma: +0/-0
    • View Profile
Question about friends
« on: November 08, 2009, 05:21:45 am »
Consider this code:

class A
{
public:
  int GetX() { return x; }
private:
  int x;
};

class B
{
private:
  A theClassA;
};

class C
{
private:
  B theClassB;
  int myCopyOfX;
public:
  int GetX_FromA() { myCopyOfX = theClassB.theClassA.GetX(); }
};

This won't work, of course, because theClassB is a private member of class B, and theClassA is a private member of class A, so the compiler will complain about trying to access private members.  I can fix this by making theClassB and theClassA public, which violates the guideline about making attributes public.  I can also fix it with friends:

class A
{
public:
  int GetX() { return x; }
private:
  int x;

  friend class B;
  friend class C; // maybe I have to do this too, not sure, but don't think so...
};

class B
{
private:
  A theClassA;

  friend class C;
};

class C
{
private:
  B theClassB;
  int myCopyOfX;
public:
  int GetX_FromA() { myCopyOfX = theClassB.theClassA.GetX(); }
};

I know that some OOAD types object to the use of friends in general, saying that they break encapsulation and betray poor design.  I would claim that using friends beats making theClassA and theClassB public because friends, at least, allow one to maintain at least some control over access.

What do you all think?

« Last Edit: November 08, 2009, 05:22:00 am by rkt-med »

Hermes

  • EA User
  • **
  • Posts: 41
  • Karma: +0/-0
    • View Profile
Re: Question about friends
« Reply #1 on: November 08, 2009, 10:05:21 pm »
Dear EricP

IMHO Friend specifier gives only a shortcut beetween ecapsulted attributes/methods, and this is payed with the cons of ecapsulation breaking.

A nice couple of questions I think may drive your design choice is:
 - Why I need friends?
 - Can I avoid use of friends?

For the second question, I can answer you by the following code:
.................
class A
{
public:
 int GetX() { return x; }
private:
 int x;
};

class B
{
private:
 A theClassA;

public int GetX_FromA() { return theClassA.GetX(); }

};

class C
{
private:
 B theClassB;
int myCopyOfX; /* why do you need this copy? */
public:
 int GetX_FromA() { return theClassB.GetX_FromA(); }
};

....................

So You can always avoid using of friends.

Of course you have to wrap in class b whatever you need in from A in C.

If the class B seems you to be a "big wrapper" of A, is possible that you need B to be just an interface, or you could just extend A by B: Design is making choices!  :)

For the first question, it depends...
(the only example AFAIK that gives you a real advantage of using firends operator is when you overloads operators (C++) )

I hope this helps.
/D
« Last Edit: November 08, 2009, 10:12:12 pm by hermes »

g.makulik

  • EA User
  • **
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Question about friends
« Reply #2 on: November 08, 2009, 10:21:31 pm »
Hi Eric,

I agree with Hermes advice to avoid using friend in general. See also my answer to your other forum question about this topic. When I wrote this, I didn't see the problem you want to solve with a friend dependncy, is that simple.
Since your question is more related to C++, than to UML, I have some C++ specific notes:
I would advise you to consider providing getter/setter operations for your private members in a class. With C++ you can achieve a very fine granularity of the accessor semantics using the const keyword. Some samples for getters/setters:

Code: [Select]
class X;

class A
{
    ...
public:
    const X & getX_1() const { return x1; }
    X & getX_2() { return x2; }

    void setX_1(const X & newValue) { x1 = newValue; }
    void setX_2(X & newRef) { x2 = newRef; }
private:
    X x1;
    X & x2;
}
[size=9](Small edits on the code sample, was written after I woke up today ...)[/size]

getX_1() doesn't allow an accessing client of A to change the x attribute, where getX_2() does. The setX_1() operation indicates that the x attribute is kind of value type used by A (Value types in C++ should have a copy constructor and overridden assignment operator, google for 'nice class' also). The same pattern also works for references as shown with setX_2().
Setup proper constness semantics for your classes in C++ from the very beginning. It will be always hard to overwork this later, when your desgin evolved to interactions between a couple of classes.

Regarding modelling this in UML, have a look at EAs isQuery operation option, and 'isFixed' option for parameters (simply reverse engineer the sample to get a grip).

Just my 0.02 EUR
Günther
« Last Edit: November 09, 2009, 02:48:46 am by g.makulik »
Using EA9.3, UML2.3, C++, linux, my brain, http://makulik.github.com/sttcl/