0
\$\begingroup\$

I did the following Excercise:

simulate single inheritance in C. Let each "base class" contain a pointer to an array of pointers to functions (to simulate virtual functions as freestanding functions taking a pointer to a "base class" object as their first argument). Implement "derivation" by making the "base class" the type of the first member of the derived class.

For each class, initialize the array of "virtual functions" appropriately. To test the ideas, implement a version of "the old Shape example" with the base and derived draw() just printing out the name of their class. Use only language features and library facilities available in standard C.

I wonder if my approach is good? And as a side question: Is OOP relevant in practice with using c?

Edit: the goal is to simulate c++ like OOP constructs with the limited features of c.

#include <stdio.h>

typedef void(*pfct)(struct Shape*);

typedef struct {
    pfct draw;
}Vtable;

typedef struct{                 // "Base class"
    Vtable* pvtable;
}Shape;

typedef struct{                 // "Derived" from Shape
    Shape shape;
    int radius;
}Circle;

void draw(Shape* this)          // "Virtual function"
{
    (this->pvtable->draw)(this);
}

void draw_shape(Shape* this)    
{
    printf("Drawing Shape\n");
}

void draw_circle(Shape* this)
{
    Circle* pcircle = (Circle*)this;
    printf("Drawing Circle with radius = %i\n",pcircle->radius);
}

Shape* init_shape()
{
    Shape* pshape = malloc(sizeof(Shape));
    Vtable* pvtable = malloc(sizeof(Vtable));
    pvtable->draw = &draw_shape;        
    pshape->pvtable = pvtable;
    return pshape;
}

Circle* init_circle(int radius)
{
    Circle* pcircle = malloc(sizeof(Circle));
    pcircle->shape = *init_shape();
    pcircle->shape.pvtable->draw = &draw_circle;
    pcircle->radius = radius;
    return pcircle;
}

int main()
{
    Shape* myshape = init_shape();
    Circle* mycircle = init_circle(5);
    draw(myshape);
    draw(mycircle);

    getchar();
    return 0;
}
\$\endgroup\$

closed as off-topic by πάντα ῥεῖ, Stephen Rauch, IEatBagels, Raystafarian, Billal Begueradj Jun 27 '18 at 4:40

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Lacks concrete context: Code Review requires concrete code from a project, with sufficient context for reviewers to understand how that code is used. Pseudocode, stub code, hypothetical code, obfuscated code, and generic best practices are outside the scope of this site." – πάντα ῥεῖ, Stephen Rauch, IEatBagels, Raystafarian, Billal Begueradj
If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    \$\begingroup\$ I think your exercise's explanation should be a little more.. explained. It isn't clear what you are supposed to achieve. \$\endgroup\$ – IEatBagels Jun 26 '18 at 19:43
  • \$\begingroup\$ The exercise appears to be #21 in Chapter 27 of Bjarne's C++ book Programming Principles and Practice Using C++ \$\endgroup\$ – Sᴀᴍ Onᴇᴌᴀ Jun 26 '18 at 19:44
  • \$\begingroup\$ I changed the title so that it describes what the code does per site goals: "State what your code does in your title, not your main concerns about it.". Feel free to edit and give it a different title if there is something more appropriate. \$\endgroup\$ – Sᴀᴍ Onᴇᴌᴀ Jun 28 '18 at 15:17
1
\$\begingroup\$

Simulate single inheritance in c
I wonder if my approach is good?

Function consistency

I'd expect ..._circle(Shape* this) functions to take Circle* this. Let the draw() play with the pointer conversions.

void draw(void* this) {
  Shape* pthis = this;
  (pthis->pvtable->draw)(pthis);
}

void draw_circle(Circle* this) {
    printf("Drawing Circle with radius = %i\n",this->radius);
}

// No longer generate a warning
draw(mycircle);

Naming convention

For type Shape, code uses ..._shape, the undefined struct Shape and Vtable. I'd expect greater uniformity - perhaps Shape_init(), Shape_draw(), Shape_Vtable, etc.

For Circle, use Circle_draw(), Circle_init(), etc. and not ..._circle().

Avoid text case changes.

Avoid anonymous struct Shape

This problem hints that code is using C++ to compile C code. Best to use C for C code.

Change typedef void(*pfct)(struct Shape*); to typedef void(*pfct)(Shape*); and move after typedef struct{ ... }Shape;

Missing companion free()

A companion to ..._init(), a ..._uninit() should exist.

Organization

Put Shape code in one place (or file) and Circle in another.


Consider allocating to the object, not the type

It is easier to code right, review and maintain.

// pshape = malloc(sizeof(Shape));
pshape = malloc(sizeof *pshape);

Error checking

Robust code checks memory allocation.

pshape = malloc(sizeof(Shape));
if (pshape == NULL) Handle_OutOfMemory();
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.