Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve encapsulation in C

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:

  1. 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.

  2. 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".

like image 268
Svetoslav Kolev Avatar asked May 13 '11 20:05

Svetoslav Kolev


People also ask

How can encapsulation be achieved?

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.

Is encapsulation is possible in C language?

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.

What is encapsulation and how it is achieved?

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.

What is encapsulation in C with example?

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; } };


1 Answers

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.

like image 88
Victor Sorokin Avatar answered Sep 19 '22 20:09

Victor Sorokin