Getting into "Object Oriented" spirit.

Hello everybody.
So I've been using C for a while and got comfortable with it but now I
want to start learning C++ and for that I decided a good strategy would be
to convert some of my old project from C to C++.
I've been doing just that and so far had no trouble because it is easy
to see how a small program of 100 lines of code that is written procedurally
can be transformed using ideas of encapsulation, instantiation, inheritance, etc.
However, right now I'm working on a program that uses stack and linked list
to perform "infix to postfix" conversion and I'm having trouble with a
structure of my cpp version of program.
When written in C, I have three files and I "dig" this arrangement. I like it.
I have an interface declared in dot h file and all necessary functions are
defined in dot c file. The third file contains "main" which holds my
conversion algorithm. Simple.
Question is, how can ideas of Object Oriented programming be used to come up
with a better structure of the above program? And what is going to be better
about it?

Thank you.
When written in C, I have three files and I "dig" this arrangement. I like it.
I have an interface declared in dot h file and all necessary functions are
defined in dot c file. The third file contains "main" which holds my
conversion algorithm. Simple.
That's ok. In OOP you'll have the functions 'integrated' within the class/struct. You'll access the data/function not longer globally but tied to the information. See:

http://www.cplusplus.com/doc/tutorial/classes/
Any chance we could see the C code for your conversion program?

The same interface in headers and implementation in cpp applies in the OO world as much as in the procedural world.

It is possible that your code isn't complicated enough to benefit from a full on OO approach.

In C++ code there's no need for custom implementations of a stack or linked list as these are provided by the standard library. (Are these what are in your .h and .c files?)

Andy
Yep. That's what I got.

stack.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#ifndef STACK_H_
#define STACK_H_

#include <stdio.h>
#include <stdlib.h>

#define CAPACITY 10// MAX stack size

typedef struct stack_struct *StackPtr;
typedef struct stack_struct StackStruct;
typedef char *  ElemType;

#define FORMAT_STRING "  %s\n"

extern StackPtr stk_create();

extern void stk_free(StackPtr s);

extern int stk_push(StackPtr s, ElemType val);

extern ElemType stk_pop(StackPtr s);

extern int stk_is_full(StackPtr s);

extern int stk_is_empty(StackPtr s);

extern int stack_size(StackPtr s);

extern void stk_clear(StackPtr s);

extern void stk_print(StackPtr s);

extern StackPtr stk_clone(StackPtr s);
#endif


stack.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include "stack.h"

struct stack_struct {
    int curr_capacity;
    int top;
    ElemType *items;
};

StackPtr stk_create(){
    StackPtr s = malloc(sizeof(struct stack_struct));
    s->items = malloc(sizeof(ElemType)*(s->curr_capacity));
    s->curr_capacity = CAPACITY;
    s->top = -1;
    return s;
}

void stk_free(StackPtr s) {
    free(s);
}

int stk_push(StackPtr s, ElemType val){
    if(stk_is_full(s))
       stk_clone(s);  
       //return 0;
    s->top++;
    s->items[s->top] = val;
    return 1;
}

ElemType stk_pop(StackPtr s){
    if(s->top == -1)
    abort();
    s->top--;
    return s->items[s->top+1];
}

int stk_is_full(StackPtr s){
    return s->top == CAPACITY-1;
}

int stk_is_empty(StackPtr s){
    return s->top == -1;
}

int stk_size(StackPtr s) {
    return s->top+1;
}

void stk_clear(StackPtr s){
    s->top = -1;
}

void stk_print(StackPtr s) {
    int i;
    printf("\n----TOP-----\n");

    for(i=s->top; i>=0; i--) {
        printf(FORMAT_STRING, s->items[i]);
    }
    printf("---BOTTOM---\n");
}

StackPtr stk_clone(StackPtr s){
    ElemType *new_items = malloc((2*s->curr_capacity)*sizeof(ElemType));
    int i;
    for(i=0;i<=s->top;i++){
        new_items[i] = s->items[i];
    }
    free(s->items);
    s->items = new_items;
    return s;
}



main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stack.h"
#include <ctype.h>

int main(int argc, char *argv[]){
    
    StackPtr sptr = stk_create();
    int i;
    char *a;
    char *b;
    char *str_tok;
    for(i=1;i<argc; i++){
       if(isdigit(argv[i][0])){
          stk_push(sptr,argv[i]);
       }
       else if(strcmp(argv[i],"-")==0 && isdigit(argv[i][1])){
          stk_push(sptr,argv[i]);
       }
       else if(strcmp(argv[i],"*")==0||strcmp(argv[i],"/")==0||strcmp(argv[i],"-")==0||strcmp(argv[i],"+")==0){
          a = stk_pop(sptr);
          b = stk_pop(sptr);
          str_tok = malloc(sizeof(char)*256);
          sprintf(str_tok,"(%s %s %s)",b,argv[i],a);
          stk_push(sptr,str_tok);
          str_tok = NULL;
       }
    }
    stk_print(sptr);
}
Just some comments on your C code:

By convention, when you clone an object you get an entirely new object that exists in addition to the old object. Your "clone" function only modifies the original.

The condition on line 18 in your main function can never evaluate to true. strcmp returns 0 when the entirety of the strings being compared are equal. So, the first part of the condition only evaluates to true when the string is "-" in which case the value of the second element will be the nul value terminating the string.

Line 24 in your main function is not matched by a complementary free so you're leaking memory.

In your stk_create function you are using an uninitialized value to feed to malloc. That's not good. (Line 12 should precede line 11 in stack.c.)

What are you trying to do object-oriented wise? Convert your stack code into a class?

I would say that your code is object-oriented whether or not you're using explicitly using the word "class".

In this sense, C++ just makes the functions associated with a stack explicitly part of the "class" of a stack instead of being "free" functions: object_foo(Object *obj, int a) becomes obj.foo(int a);

Also C++ has function overloading so that you don't have to have unique names for everything (a "pop()" function could apply to both a "stack" and a linked list or whatever). C++ also has "RAII" so that the end user of an Abstract Data Type doesn't have to worry about moving pointers around and deallocating stuff.

In your code, the only place you seem to actually free your items is in stk_clone, so I think you have a bit of a memory leak there unless I missed a line of code. (I would have yorur stk_free function free both the stack itself and the items).

Also just an opinion, but at first glance of a variable such as "top", and it would let me to believe its a variable for the top value itself, and not an index marker. I'd rather call it "size" or something along those lines.
Another opinion: There's probably no need to dynamically allocate the stack object itself, just the dynamic array of items.



Last edited on
Topic archived. No new replies allowed.