Originally posted by: Nothinman
Disagreed. The moment you declare something public, it's open game to ANYONE/ANYTHING (all classes, external functions, etc). The C++ "friend" clause lets you allow SPECIFIC CLASSES to have open access to a particular class, not EVERYTHING.
I realize the difference, but it seems to me that if you start declaring classes as friends you're avoiding they key reason to mark things private in the first place.I would think it would be better design to either incorporate the 'friend's functionality in the other class, hell they're dependent on each other now anyway, or make the data public (or atleast have a public setup/set function) because you've obviously found a reaon to want to update it from outside that class.
There are plenty of legitimate reasons for friend classes & functions. The classic example for friend functions is overloading the '<<' and '>>' operators for IO.
The case for friend classes is a little tougher, but it still exists. I'll look at it in terms of your counter arguments...
incorporate the 'friend's functionality in the other class
A class should always be an 'is a' type of object. ie. it should represent a distinct & narrowly defined entity. To combine two classes because they need to interact would muddy this considerably.
make the data public (or atleast have a public setup/set function) because you've obviously found a reaon to want to update it from outside that class.
A friend class or function does not necesarily update or change data in the classes it has friend relationshiop(s) with, but in any case, there are legitimate reasons not to make the data, or access functions needed public. For example, one place I use friend is in my vector & matrix classes. Look at the example of matrix - vector multiplication.
Array A(3, 3); // a 3x3 array
Vector x(3), y(3); //vectors of size 3
//...initialization...
x = A*y;
Now, I could certainly implement this via the public api ... the overloaded '[]' and '()' operators. But those operators on the array side have to calculate row offsets, on the array & vector side they could have range checking turned on, etc. Using the pyublic API would be VERY slow compared to an algorithm that does pointer math directly on the raw internal representation for both objects. And of course, making that raw internal representation public would be a big mistake.
Here's what the public data access functions look like for example:
class Vector
{
public:
virtual double &operator[](int c)
{
#ifdef DEBUG
check_index(c);
#endif
return pt[c - 1]; //API index starts @ 1, internal representation starts @ 0
}
}
class Array
{
public:
virtual double &operator()(int r, int c)
{
#ifdef DEBUG
check_index(r, c);
#endif
return pt[(r - 1)*columns + c - 1];
}
}
Here is the implementation of the Array- Vector multiplication
Vector Array:: operator*(const Vector &x) const
{
#ifdef DEBUG
if(x.size() != columns)
array_error("ERROR: Incompatible Array & Vector sizes in call to Array:: operator*(Vector)", 2);
#endif
Vector T(rows);
int i, j;
T.zero();
double *rPT = T.pt; //pointer to the start of the result Vector representation
double *xPT; //pointer to the start of the x Vector representation
double *PT = pt; //pointer to the start of the Array representation
for(i=1; i<=rows; i++)
{
xPT = x.pt;
for(j=1; j<=columns; j++)
{
*rPT += *(PT++) * *(xPT++);
}
rPT++;
}
return T;
}
I can assure you that this is significantly faster then using the public api (overloaded '[]' and '()' operators)
Another case in which I use class friends is my satellite, ground point and sensor classes. The sensor class has legitimate reasons to need direct access to the internal representations of the satellite & ground point classes. A sensor object can be attached to either of these. But the internal representations of these classes should not be publicly exposed because manipulations of them have other repercussions within the class that could'nt be easily handled.