I am not sure that what I am trying to do is called encapsulation, but it's an OOP concept. I am implementing a binary tree and in particular the insert function:
typedef struct __node* tree;
typedef struct __node { void* data; tree l,r; } node;
typedef struct {int (*cmp)(void* a,void* b); tree root;} avl_tree;
....
void tree_insert(tree node, tree* root, int (*cmp)(void* a,void* b))
{
if (*root==NULL) { *root=node; return; }
int c1 = cmp(node->data, (*root)->data);
if (c1==-1) tree_insert(node, &((*root)->l), cmp);
}
tree tree_new_node(void*data){ tree a = malloc(...); ... return a; }
void avl_insert(void* data, avl_tree* a)
{
tree_insert(tree_new_node(data), &(a->root), a->cmp);
....
}
The module is to be used through the avl_insert
function which is given a pointer to the relevant balanced tree avl_tree
which contains the pointer to the raw tree as well as a pointer to comparator. Now, it should obviously call tree insert
and tree_insert
should have access to the comparator as well as to the node I am currently inserting. The function walks on a binary tree so it's naturally recursive. However, if I give it the comparator and the current node as parameters they will be passed with each recursive invocation which is not necessary since they will always be the same.
I would like to avoid having to do so. I have not been able to come up with a clean and nice solution. These are the options that I could think of:
Use a C++ class and have the tree_insert
function be a method of avl_tree
class. Then it would have access to the comparator through the this
pointer. The problem with this solution is that I want to use C not C++. Besides, it won't eliminate the passing of the current node parameter.
Use static members inside the function (or global data). I am not sure I can cleanly initialize them at each avl_insert
call. Besides, this solution is not thread safe.
Now that I think about it this seems very easy to implement in a functional programming language. I wonder, is this a fundamental problem with C or is it just me not knowing how to do it. What would be the cleanest way to achieve this?
Thank you!
After I thought about Victor Sorokin's answer I read about the this
pointer and it turns out it is an implicit parameter in every member function call. Now that I think about it it seems the only logical solution. Each invocation of the tree_insert
function needs to know the address of the structure it's operating on. Not even in a functional language could you avoid that extra pointer...
A possible solution would be to keep a pointer to the main tree structure in each node..
So it's a fundamental "problem".
How can Encapsulation be achieved? Explanation: Using access specifiers we can achieve encapsulation. Using this we can in turn implement data abstraction. It's not necessary that we only use private access.
It is one of the core features of Object-oriented languages. However, it is not only limited to OOP languages only. In C, encapsulation has been despite the absence of private and public keywords. Encapsulation is being used by various other programming languages like C#, C++, PHP, JAVA as well.
Encapsulation in Java is a powerful mechanism for storing the data members and data methods of a class together. It is done in the form of a secure field accessible by only the members of the same class.
In general, encapsulation is a process of wrapping similar code in one place. In C++, we can bundle data members and functions that operate together inside a single class. For example, class Rectangle { public: int length; int breadth; int getArea() { return length * breadth; } };
One fun approach that could be used to achieve encapsulation is looking into assembly code emitted by C++ compiler and then translating it into appropriate C code.
Another, more conventional, approach would be to use some C object library, like GLib.
I think, though, these two methods will give similar results :)
By the way, first option you mentioned is just as vulnerable to threading issues as second. There's no implicit thread-safety in C++.
"OOP" C code I have seen in Linux kernel (file-system layer) is mostly concerned with polymorphism, not with encapsulation. Polymorphism is achieved by introducing structure enumerating possible operations (as pointers to functions). Various "subclasses" then created, each initializing this structure with it's own set of implementation methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With