Difference Between C and OOPs Languages (C++/C#/Python)

Difference Between C and OOPs Languages (C++/C#/Python)

Why C?

C language has been the most important programming language for decades.

  • Actually, for the embedded systems it is still the best option.
  • It is the most efficient language, as after the program compilation/link the executable file is the smallest and running faster than if written in any other programming language.
  • Programs written in C can be easily mixed with the assembly code, which is the lowest level (i.e. closest to the hardware platform) programming technique.
  • You can write completely mixed programs, in which C functions/routines and assembly routines call each other, usually those most time-critical written in the assembly code.  

However, the C language has one drawback.

Drawback of C Language

And it is the vulnerability towards any, though unwanted program changes due to the exposed, and thus easily accessible global variables.

If you are the only one working on a project, then yes, you can “guard” all your actions so as not to cause any such problems.

But imagine large projects, which require hundreds of code designers working on the same project, where everyone has full access to any global variable. 

The only solution to avoid such problems is to hide (encapsulate) variables as much as possible inside some data structures.

Use of Object-Oriented Languages over C

The object-oriented languages, like C++, C# and Python are far safer from this point of view, as you can encapsulate all the variables inside the structures called classes.

(Encapsulation is one of the major concepts in object-oriented programming.)

One interesting question is, how far we can go in C programming, to “mimic” the same approach as those higher-level, object-oriented programming languages have.

Example:

So, let’s look at the following program.

In this program, we will try to encapsulate as many items as possible. Let’s say that our program will deal with only two variables and one function. So, at first, we will try to place all three items into one structure.

First let’s write the header file, ClassTest.h, which will keep all the needed type definitions and declarations.

#ifndef CLASS_TEST
#define CLASS_TEST
 
// ClassTest type declaration has to precede all declarations, 
// which use "ClassTest".
typedefstructClassTest;
 
// proc function type declaration has to precede all declarations, 
// which use "proc".
typedefvoid (*proc)(ClassTest*);
 
structClassTest 
// This is finalization of the ClassTest type definition
{
  int id;
  char* n;
  procmyProc;
};
 
// Those two functions (here are their prototypes) 
// will be used as constructor/destructor 
ClassTest* ConstrClass(int, char*, proc);
voidDestrClass(ClassTest*);
 
#endif

In such a way now we have defined a ClassTest structure, which will keep three items in one place.

However, all the functions for the “object construction and destruction” (including the internal myProcfunction) have to be defined “outside” the ClassTeststructure. We will define them (implement their bodies) in a separate source file, ClassTest.c:

#include<stdio.h>
#include<stdlib.h>
#include"ClassTest.h"
 
ClassTest* ConstrClass(inti, char *n, procmyP)
{
  ClassTest *objTest = (ClassTest*)malloc(sizeof(ClassTest));
  if(objTest)
  {
    objTest->id = i;
    objTest->n = n;
    objTest->myProc = myP;
    returnobjTest;
  }
  returnNULL;
}
 
voidDestrClass(ClassTest* obj)  
{
  if (obj != NULL)
  free(obj);
}

Finally, we can write a source code (in a separate file), which will use all the information found in the ClassTest.h/ClassTest.c pair.

Let’s call this source file Program.c.

#include<stdio.h>
#include<stdlib.h>
#include"ClassTest.h"
 
 
void Show(ClassTest* obj)  
// This function conforms the "proc" declaration
{
  printf("Object #%d is showing: ", obj->id);
  while (*obj->n != '\0')
    printf("%c", *obj->n++);
  printf("\n");
}
 
void main()
{
  char st1[] = "First String";
  char st2[] = "Second String";
 
  ClassTest* obj1 = ConstrClass(1, st1, Show);
  if (obj1)
  {
    obj1->myProc(obj1);
  }
 
  ClassTest* obj2 = ConstrClass(2, (char*)"Second String", Show);
  if (obj2)
  {
    obj2->myProc(obj2);
  }
 
  DestrClass(obj1);
  DestrClass(obj2);
}

At first, we needed to define a function(s), to which the procmyProc pointer will be referring. We can have just one such function, but we may have more functions, and each “object” can get a different one.

Finally, we could write the main() function. Before we can construct “objects”, we need to have prepared all the parameters, which ConstrClass() requires.

The first parameter is an integer value, which usually will be provided either by some other function or the user will enter it (via scanf(), for example). For simplicity, we just place these “Object IDs” directly.

The second parameter has to be a reference to an array of characters (text string), which has to end with the terminal zero (‘\0’). We defined such parameter(s)  as the char st1[] and char st2[] arrays. Again, this is fine for demonstration purposes, in real life this information will be provided from other parts of a program (or entered by the program user). 

As we have all (three) parameters ready, the main() function can create the obj1 object. If the object is successfully created, we can call its method, myProc(). We have to use the standard access operator, ->, as obj1 is a pointer type.

Then we can create the second object, obj2. The second parameter of this object in our case is directly a string, which is a const char* (read-only) data type and the compiler will place it into the Text/Code memory segment, together with the program code.

We need to use the (char*) casting to make this text string compatible with what is required from the second parameter definition.

Difference between C and OOPs

What can we learn from the program above?

That even C allows us to write clear, safe programs, very close to those written in genuine OOP languages. However, there are still certain shortcomings from this point of view.

For example, the Show() function, which was supposed to be an exclusive method/member of the ClassTest objects, still can be called directly, outside of any obj1 or obj2  object.

In addition, even if Show() is a member of the ClassTest structure type, it can’t directly access any other structure members, as its body couldn’t be defined inside the structure. It has to get a reference (as an argument) to the object of which this function is a member!

This is not a very nice feature, isn’t it?

Then, even though those three “object” items are encapsulated inside the structure, they can’t be hidden there, so their values can be accessed and potentially modified.

So, there are still aspects, which prevent the C language from being, even close to object-oriented programming languages.

OOPs Concepts in Other Languages

C++:

Its C++ “extension” has all the attributes of an OOP language, but as the user still can mix the traditional, C coding, even C++ can’t be considered as a genuine OOP language.

C#:

The C# programming language, for example, is already considered a genuine OOP language.

Python:

The ultimate candidate for the “purest” OOP language is Python. There, every single item (like a = 10) already represents an entire object!

If you are interested in Python, get access to a complete Python tutorial.

If you have any questions or thoughts about OOPs concepts, you can share and discuss with me by commenting below.

Leave a Reply

Your email address will not be published. Required fields are marked *