views:

84

answers:

3

I am writing a B-link tree and its attendant sub classes like a data page class and a node class etc.

I was wondering is there a way to protect the public interfaces of the nodes and pages such that only the b-link tree class itself can access them, WITHOUT simultaneously exposing the private methods of the pages and nodes to the b-link class?

IE I have already thought of simply changing the 'public' interface of the pages and nodes into the protected category and then declaring the B-link tree as a friend but that gives the b-link tree access to private methods that I want to stay private.

+6  A: 

Off the top of my head, you could do something like:

class FooAdapter;

class Foo
{
private:
     void funcToExpose();
     void funcToHide();
     friend FooAdapter;
};

class FooAdapter
{
private:
     Foo foo;
     void funcToExpose() { foo.funcToExpose(); }

     friend SomeFriend;
};

(Not compiled or tested, but you should get the idea.)

Oli Charlesworth
+1. You can also use a somewhat similar pattern using inheritance for "virtual" friends.
DeadMG
@DeadMG: Could you elaborate?
Oli Charlesworth
If you friend the base class, it can then implement methods that effectively wrap the intended methods- allowing the derived classes to access them as if they were friends.
DeadMG
Hmm. This makes sense to me. I am kinda ticked at myself for not thinking of it. Just to make certain I understand it, this is sort of an example of my thinking. Say I have a class Node. I then have some class NodeAdapter. Node has NodeAdapter as a friend and NodeAdapter has BLinkTree as a friend. My BLinkTree class then declares a private member variable of type NodeAdapter and handles everything through that. It seems to me that the variable within a variable like this would cost a *little* more in memory overhead (though very little), do you think it would be enough to affect anything?
James Matta
@James: I would imagine that with a decent compiler, and with `FooAdapter` written as a set of `inline` functions, the cost in memory and cycles could be zero. If not, the cost will certainly be tiny. If you're concerned, I'd measure it and find out!
Oli Charlesworth
I actually did measure it, mostly for laughs really since as you pointed out the cost would be tiny. The cost is measurable in memory consumption on SOME compilers, in no compiler is there a cost in cycles, which is sort of what I expected since I did everything with inlines. I wasn't really offering it as a criticism just as a conjecture. The things I want to use this for are so very very IO bound that cycles and even memory don't count for too much.
James Matta
Just out of interest, what is the memory cost?
Oli Charlesworth
The cost is a few bytes. My guess is that the compilers in question are not optimizing the adapter class completely out of existence so they are having to maintain a this pointer or something for each instance of the adapter class. This happened with a really early g++ though, like 2.00 (from an ancient machine in the lab I work in).
James Matta
A: 

If you don't want the interfaces of the nodes and pages to be exposed in your API then just declare them inside your b-link implementation file. If the b-link implementation spans more than one file, then put the node and page class declarations in an implementation-only header file (co-located with your implementation files, not with your API headers).

gregg
+2  A: 

You can try defining your attendant sub classes in an anonymous namespace in the same translation unit as the b-tree. Supposedly that will make those clases inaccesible from outside that translation unit.

See http://stackoverflow.com/questions/154469/unnamed-anonymous-namespaces-vs-static-functions

gpeche
This idea is interesting but I do not think it would work properly. The logic in the nodes and pages is heavy enough that they should have their own .cpp files which makes putting them in an unnamed namespace in the BLinkTree file kind of hard.
James Matta
`#include` your implementation files inside the anonymous namespace
gpeche