Board index » cppbuilder » Question about friends and functions

Question about friends and functions


2007-10-12 03:45:04 AM
cppbuilder11
Hi there
I have to classes:
class TFile
{
TFile(TFolder* aOwner, int aSize)
{
aOwner->IncreaseTotalSize(aSize);
}
};
class TFolder
{
protected:
IncreaseTotalSize(int Value);
};
I would like to give TFile acces to the function
IncreaseTotalSize and only that function.
Is that possible ??
If so how ??
Thanks in advance
Asger
 
 

Re:Question about friends and functions

Asger Jørgensen < XXXX@XXXXX.COM >writes:
Quote
Hi there

I have to classes:

class TFile
{
TFile(TFolder* aOwner, int aSize)
{
aOwner->IncreaseTotalSize(aSize);
}
};

class TFolder
{
protected:
IncreaseTotalSize(int Value);
};

I would like to give TFile acces to the function
IncreaseTotalSize and only that function.

Is that possible ??
If so how ??
One way is to use inheritance and to make the function virtual. The
derived class implements the virtual function privately, and the base
class make the declaration private but makes TFile a friend. If
TFolder inherits publically from this base class, then it can "upcast"
the pointer and then call through it:
#include <iostream>
class TIncreaseTotalSize
{
public:
~TIncreaseTotalSize(){}
private:
virtual void IncreaseTotalSize(int Value) = 0;
friend class TFile;
};
class TFolder : public TIncreaseTotalSize
{
public:
private:
virtual void IncreaseTotalSize(int Value)
{
std::cout << "Increasing size by " << Value << std::endl;
}
};
class TFile
{
public:
TFile(TFolder* aOwner, int aSize)
{
// **************
// note: upcast conversion TFolder to TIncreaseTotalSize,
// since we're a friend of the base but not the derived type.
TIncreaseTotalSize * baseOwner = aOwner;
baseOwner->IncreaseTotalSize(aSize);
}
};
int main()
{
TFolder folder;
TFile tf(&folder, 999);
}
Another way is to use a helper nested class that ONLY has one member, and
it is granted friendship, and that class grants friendship to your
external file. It makes for a little less "pretty" syntax, though.
For example:
#include <iostream>
//
// Nobody outside TFolder can call IncreaseTotalSize
// Except for friends. The only friend is IncreaseTotalSize_Access
// and IT only has one friend, TFile.
//
class TFolder
{
public:
class IncreaseTotalSize_Access:
// ...
private:
friend class IncreaseTotalSize_Access;
void IncreaseTotalSize(int Value);
};
void TFolder::IncreaseTotalSize(int Value)
{
std::cout << "Increasing size by " << Value << std::endl;
}
////////////////////////////////////////////////////////////
// Nested CLASS : This forwards the call into the real object.
// Only TFile can invoke the call() function, since the
// whole class is private, and only TFile is a friend
//
class TFolder::IncreaseTotalSize_Access
{
friend class TFile;
static void call(TFolder * obj, int Value)
{
TFolder::IncreaseTotalSize(obj, Value);
}
};
class TFile
{
public:
TFile(TFolder* aOwner, int aSize)
{
// ugly syntax for calling the function
TFolder::IncreaseTotalSize_Access::call(aOwner, aSize);
}
};
int main()
{
TFolder folder;
TFile file(&folder, 999);
}
There are some other ways, though. For one, using a virtual function:
--
Chris (TeamB);
 

Re:Question about friends and functions

"Asger Jørgensen" < XXXX@XXXXX.COM >wrote in message
Quote
I would like to give TFile acces to the function
IncreaseTotalSize and only that function.

Is that possible ??
If so how ??
TFile needs to be declared as a 'friend' of TFolder:
class TFolder
{
friend class TFile;
protected:
IncreaseTotalSize(int Value);
};
TFile can then access all of TFolder's 'private' and 'protected' members.
Gambit
 

{smallsort}

Re:Question about friends and functions

"Chris Uzdavinis (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote
One way is to use inheritance and to make the function virtual.
I don't understand why that would be needed. Why not just make TFile be a
fiend of TFolder directly? Is it just because you are trying to isolate
TFile from accessing TFolder's other private members?
Gambit
 

Re:Question about friends and functions

"Remy Lebeau \(TeamB\)" < XXXX@XXXXX.COM >writes:
Quote
"Chris Uzdavinis (TeamB)" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...

>One way is to use inheritance and to make the function virtual.

I don't understand why that would be needed. Why not just make
TFile be a fiend of TFolder directly? Is it just because you are
trying to isolate TFile from accessing TFolder's other private
members?
Yes. He asked how to grant friendship only to one (and only one)
particular member function.
The virtual interface is probably the cleanest way to give partial
friendship, but other implementations also are possible, as I showed.
Another technique I didn't show is using a "key" class, where the
functions are public but they take a dummy key parameter, and nobody
has an instance of key except for the objects or classes to which it
was explicitly given. If the key type itself is a private nested type
of the class, then nobody can get an instance of it unless it's
explicitly given.
--
Chris (TeamB);
 

Re:Question about friends and functions

Chris Uzdavinis (TeamB) < XXXX@XXXXX.COM >writes:
Quote
"Remy Lebeau \(TeamB\)" < XXXX@XXXXX.COM >writes:

>"Chris Uzdavinis (TeamB)" < XXXX@XXXXX.COM >wrote in message
>news: XXXX@XXXXX.COM ...
>
>>One way is to use inheritance and to make the function virtual.
>
>I don't understand why that would be needed. Why not just make
>TFile be a fiend of TFolder directly? Is it just because you are
>trying to isolate TFile from accessing TFolder's other private
>members?

Yes. He asked how to grant friendship only to one (and only one)
particular member function.
(Argh. It's hard to talk about friends, granting access, and so on,
without ambiguity.)
I'm trying to say that he wanted to grant a limited friendship to a
class, such that it could only access a single private member, rather
than all private (and protected) members.
--
Chris (TeamB);
 

Re:Question about friends and functions

Thanks to all for explaining
Kind regards
Asger
 

Re:Question about friends and functions

might use the hack method here...
class TFolder
{
protected:
IncreaseTotalSize(int Value);
};
class TFolderHack : public TFolder // visible only to TFile
{
public:
IncreaseTotalSize(int Value)
{
TFolder :: IncreaseTotalSize(Value);
};
};
class TFile
{
TFile(TFolder* aOwner, int aSize)
{
((TFolderHack *)aOwner)->IncreaseTotalSize(aSize);
}
};
I know.. but what can ya do ?
Michael
"Asger Jørgensen"wrote in message
Quote

Thanks to all for explaining

Kind regards
Asger
 

Re:Question about friends and functions

"Michael Harris" < XXXX@XXXXX.COM >writes:
Quote
might use the hack method here...
Only a few problems with this:
1) casting an object's pointer to a type that it isn't yields
undefined behavior (though it could end up working.)
2) Once you accept this kind of code into your codebase, it becomes
difficult to know when hacks are valid and when they are
inappropriate. For example, given a codebase littered with "valid"
hack type-casts, when another programmer inserts a new hack-cast,
you probably won't even notice, and you won't have any idea if it's
valid or not.
3) Encouraging people to go around the type system makes your
interfaces much harder to use. If it were conventional to
cast away the privateness of members, then users of classes must
worry about public and private/protected members, and are not able
to simply pay attention to the public interface. That requires
that peopel know implementation details about a lot more code just
to be able to use it. Not good.
4) Nothing prevents other files and other classes from using your
technique, so it doesn't really solve the initial question of
granting access to one class to one and only one member function.
Friendship is given, not taken, and the hack solution you propose
is "taking" access rather than having it be given. Since it's
undocumented, there is nothing in the code to indcate that the code
should be allowed.
In short, this wouldn't pass a code review if I were conducting it.
--
Chris (TeamB);