Why he used '->' in this code?

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think here is the third place that I asked this question. I don't dare to ask it in StackOverflow( because probably they will give down-vote to my question. well this is a primary question) and because I know here are many professional programmers then I ask it here and hope to get a decent answer.

 

I'm reading "Teach yourself C++" book by Herbert Schildt to learn C++. there is an example in chapter 10 which is tough to me. this is the code I'm talking about:
 

#include <iostream>
#include <cstdlib>
#include <cctype>

using namespace std;

class list {
public:
    list *head; // pointer to start of list
    list *tail; //pointer to end of list
    list *next; //pointer to next item
    int num; // value to be stored

    list() { head = tail = next = null;}
    virtual void store(int i) = 0;
    virtual void retrieve() = 0;
};

//create a queue-type list
class queue : public list {
public:
    void store(int i);
    int retrieve();
};

void queue::store(int i)
{
    list *item;

    item = new queue;
    if(!item) {
        cout << "Allocation error.\n";
        exit(1);
    }
    item->num = i;

    //put on end of list
    if(tail) tail->next = item;
    tail = item;
    item->next = null;
    if(!head) head = tail;
}

int queue::retrieve()
{
    int i;
    list *p;

    if(!head) {
        cout << "list empty.\n";
        return 0;
    }
    // remove from start of list
    i = head->num;
    p = head;
    head = head->next;
    delete p;

    return i;
}

// create a stack-type list
class stack : public list {
public:
    void store(int i);
    int retrieve();
};

void stack::store(int i)
{
    list *item;

    item = new stack;
    if(!item) {
        cout << "Allocation error.\n";
        exit(1);
    }
    item->num = i;

    //put on front of list for stack-like operation
    if(head) item->next = head;
    head = item;
    if(!tail) tail = head;
}

int stack::retrieve()
{
    int i;
    list *p;

    if(!head) {
        cout << "list empty.\n";
        return 0;
    }
    // remove from start of list
    i = head->num;
    p = head;
    head = head->next;
    delete p;

    return i;
}

int main()
{
    list *p;

    // demonstrate queue
    queue q_ob;
    p = &q_ob; // point to queue

    p->store(1);
    p->store(2);
    p->store(3);

    cout << "Queue: ";
    cout << p->retrieve();
    cout << p->retrieve();
    cout << p->retrieve();

    cout << '\n';

    //demonstrate stack
    stack s_ob;
    p = &s_ob; // point to stack

    p->store(1);
    p->store(2);
    p->store(3);

    cout << "Stack: ";
    cout << p->retrieve();
    cout << p->retrieve();
    cout << p->retrieve();

    cout << '\n';

    return 0;
}

This is alone tough code that I've seen so far in this book. now the questions:

1- He has defined three class pointer named head,tail and next as "list" object. are we allowed to define these pointers within class "list"? it a bit made me confused.

2- In some parts of the code you can see something e.g. this:

"tail->next = item;"

We use "->" to refer a data-object of a class. am I right? but here "tail" and "next" are both pointer to an object of "list". then why does he use "->"? totally these parts e.g. "tail->next" make me confused.

3- Would you please tell me how "store" and "retrive" functions work?

Notice this part of the book talks about polymorphism by virtual functions.

 

This topic has a solution.

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

Last Edited: Fri. May 20, 2016 - 03:51 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The -> is the member operator and is used on pointers to classes and structures in C++

 

Take the following class:

class Data
{
    int someNumber;
};

If I create an instance of Data without using new, I need to reference it using the dot (.) member operator, such as:

Data instance
instance.someNumber = 55;

If I create an instance of Data by using new, I need to reference it using the -> member operator, such as:

Data* instance = new Data();
instance->someNumber = 55;

 

My digital portfolio: www.jamisonjerving.com

My game company: www.polygonbyte.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Jamison

I completely know what you are saying but the point is that e.g. :

 

tail->next = item

Here "tail", "next" and "item" are class pointers which point to an object kind of "list" class. how is it possible?

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Surely it's because "stack" and "queue" are derived from the base class "list". So a pointer to "list" can also point to class types "stack" and "queue" too. Isn't that the very point he's trying to demonstrate here when he uses:

class queue : public list {

and

class stack : public list {

The point is that the store() and retrieve() methods in each derived class implement the virtual void members:

    virtual void store(int i) = 0;
    virtual void retrieve() = 0;

in the base class. But the other things in the base are common to all. And that includes the self-referential "list" pointers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Rohalamin wrote:

Thanks Jamison

I completely know what you are saying but the point is that e.g. :

 

tail->next = item

Here "tail", "next" and "item" are class pointers which point to an object kind of "list" class. how is it possible?

Sorry, I breezed through the OP fairly quickly as I was on my way out.

 

As clawson points out, this is what polymorphism is about. The virtual methods defined in the base class (in the example being "list") are overridden by the "queue" and "stack" classes. A "list" pointer can also point to a derived class as well ("queue" and "stack" being the derived classes).

My digital portfolio: www.jamisonjerving.com

My game company: www.polygonbyte.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It looks like head and tail are pointers to the first and last members of a list.  They are members of the list class which is the base class for the queue class.  So you get new ones for each queue class put on the list, don't you?  How does that work?  Shouldn't they be static, or located somewhere else?

 

Personally I don't like his names so I won't spend more than a couple of minutes looking at it.  Of course I don't like any names unless I wrote it.  smiley

Last Edited: Wed. May 18, 2016 - 08:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's also used in C to reference parts of a struct given a pointer to the struct.

274,207,281-1 The largest known Mersenne Prime

Measure twice, cry, go back to the hardware store

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

The example given in the book seems too complicated.  Try another book.

 

tail->next = item

is the way you add a member to the end of a linked list.

 

tail points to the last member of the list.  Each member has a pointer to the next member which is called next.  item is the pointer to a new member we want to add to the end of the linked list.

 

So we dereference tail to access the current last member.  Then we set the current last member's next pointer to be the address of the new member we want to add to the end of the list.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This example is way too complicated to explain linked lists and polymorphism.

 

Polymorphism:

 

You have a 'base' class, lets name that class Shape: 

class Shape
{
    public:
        Shape() {};
        virtual double getArea() { return area; }

    protected:
        double area;
};
// Note that protected just means "private but inheritable"

    Now we can declare a new type of Shape: rectangle

class Rectangle : public Shape
{

    public:
        Rectangle(double wid, double len);
        ~Rectangle() {};
        double getLength() { return length; }
        double getWidth() { return width; }

    private:
        double width;
        double length;
};

    Then in Rectangle constructor we put:

Rectangle::Rectangle(double wid, double len){
    width = wid;
    length = len;
    area = wid*len;
}

 

A rectangle is a Shape, and so we don't have to declare 'area' or getArea() again.

 

    now we can call Rectangle r(3.0, 2.0) in our main() 

    and call r.area() and it returns the area of Rectangle r without having to make a seperate function just for Rectangle

 

   This could now be repeated for all sorts of shapes, you can even make the class Square which inherits Rectangle !

Software Engineering student @ Reykjavik University www.ru.is

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BaldurMar wrote:

This example is way too complicated to explain linked lists and polymorphism.

Agreed. This is a bit much for an example of polymorphism. Linked lists are topic on their own and shouldn't be smashed together with polymorphism.

 

Rohalamin, I would recommend you check out some of the tutorials on www.cprogramming.com if you are looking for more learning resources. It covers inheritance, pointers, linked lists, and much more.

My digital portfolio: www.jamisonjerving.com

My game company: www.polygonbyte.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

Surely it's because "stack" and "queue" are derived from the base class "list". So a pointer to "list" can also point to class types "stack" and "queue" too. Isn't that the very point he's trying to demonstrate here when he uses:

class queue : public list {

and

class stack : public list {

The point is that the store() and retrieve() methods in each derived class implement the virtual void members:

    virtual void store(int i) = 0;
    virtual void retrieve() = 0;

in the base class. But the other things in the base are common to all. And that includes the self-referential "list" pointers.

 

Cliff I just don't get two part of this codes. this:

 

item = new queue;

In a function which is a member of "queue" it makes a "heap"(am I right?) of "queue". it's strange to me. I think I don't get it because it relates to "Data Structures" and I'm not familiar to this matter. I can see a code which it looks like this soo much here:

 

https://fa.wikipedia.org/wiki/%D8%AE%D8%B1%D9%88%D8%AC_%D8%A8%D9%87_%D8%AA%D8%B1%D8%AA%DB%8C%D8%A8_%D9%88%D8%B1%D9%88%D8%AF_%28%D8%B1%D8%A7%DB%8C%D8%A7%D9%86%D9%87_%D9%88_%D8%A7%D9%84%DA%A9%D8%AA%D8%B1%D9%88%D9%86%DB%8C%DA%A9%29#.D8.B9.D9.84.D9.85_.D8.B1.D8.A7.DB.8C.D8.A7.D9.86.D9.87

 

Another is this part:

 

if(tail) tail->next = item;
    tail = item;
    item->next = null;
    if(!head) head = tail;

Torby wrote:

It's also used in C to reference parts of a struct given a pointer to the struct.

Yes and in C++ you can use a structure instead of "Class" because they are completely the same and there is just one difference between structures and classes and that is the default situation in class" is "private" while in "structure" is "public". it means whether I write:

 

class list {
public:
    list *head; // pointer to start of list
    list *tail; //pointer to end of list
    list *next; //pointer to next item
    int num; // value to be stored
     
    list() { head = tail = next = null;}
    virtual void store(int i) = 0;
    virtual void retrieve() = 0;
};

Or I write:

 

struct list {
    list *head; // pointer to start of list
    list *tail; //pointer to end of list
    list *next; //pointer to next item
    int num; // value to be stored
     
    list() { head = tail = next = null;}
    virtual void store(int i) = 0;
    virtual void retrieve() = 0;
};

They are the same.

 

Jamison wrote:

As clawson points out, this is what polymorphism is about. The virtual methods defined in the base class (in the example being "list") are overridden by the "queue" and "stack" classes. A "list" pointer can also point to a derived class as well ("queue" and "stack" being the derived classes).

Thanks

As I answered to cliff, I just don't get two parts of the codes.

 

 

Thanks Steve and BaldurMar

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

BaldurMar wrote:
This example is way too complicated to explain linked lists and polymorphism.

And then you go on to quote the classic shape/rectangle/triangle example?!?

 

I could not agree less. I think it's a far better learning experience to show things like polymorphism being used in a real world example like lists/queues/stacks - something you might actually use in real life - rather than the hugely artificial shapes thing. I remember reading that classic example when I first explored C++ and thinking "why?".

Rohalamin wrote:
In a function which is a member of "queue" it makes a "heap"(am I right?) of "queue". it's strange to me.

I suppose it's true that this example does expect the reader to have done some previous programming and already know about concepts like lists and how you implement them.

 

I'm not sure if it helps but perhaps take a look at this old thread (might be better viewed on the legacy version of Freaks?):

 

http://www.avrfreaks.net/forum/l...

 

In that, from post #7 onwards, I talked through the very basics of creating a linked list from scratch. Initially it is just a singly-linked list with "next" pointers but in later posts I make it doubly-linked which makes traversing the list and removing elements from it easier.

Rohalamin wrote:
I just don't get two part of this codes. this:

Well that line couldn't be simpler could it? First he create a pointer to an object of type class list:

    list *item;

So that creates a variable called "item" that can hold the address of an object that is of type list or other types that are also derived from the base class type.

    item = new queue;

The "new" operator in C++ is just like malloc() i nC but for class objects. What this line is saying is: "allocate some (RAM) memory to hold a set of the variables found in the class type 'queue' then call the constuctor function for the 'queue' class to do any initialisation of those variables (and perhaps other things) it needs to do, and finally return me the address of that block of RAM which is a pointer to a class queue object". That address of class variables is then assigned to the item pointer that was previously created.

if(tail) tail->next = item;
    tail = item;
    item->next = null;
    if(!head) head = tail;

So this function itself (queue::store()) is an implementation of the store() function in the queue class which implements the "template" (probably the wrong word!) function that was given in the base class:

    virtual void store(int i) = 0;

So when queue::store() is called, like all C++ functions there is a hidden function parameter called "this" which is a pointer to a block of "queue" type variables in RAM. Within those variables are "tail", "head" and so on. So when this doe a test/assignment like:

if(tail) tail->next = item;

the "tail" here is the tail in the class vars that were passed in. So this then tests it for 0. If there are already items in the list then the pointer will already have been assigned to point to one of them and will be non-0. This first checks if that is the case, that tail is already pointing to a block of class variables. If it is then it is safe to access the "next" pointer within what it is pointing to and that is done with tail->next and this is simply assigned the address of the "item" that has just been created by new - that is another block of queue type variables.

 

Now I may have a bit of a biased view here but I cannot help thinking that it might help to understand the basics of C and struct's before you approach this? If I wrote this in C I hope it'd be obvious what's going on:

typedef struct {
    int n;
    long l;
} str_t;

void update(str_t *);

int main(void) {
    str_t mystruct;
    
    mystruct.n = 12345;
    mystruct.l = 0xBABEFACE;
    update(&mystruct);
}

void update(str_t * ptr_to_str) {
    ptr_to_str->n *= 2;
    ptr_to_str->l /= 2;
}

In this I create a type called str_t that defines a structre that contains an int and long. In main() I create an actual variable of this type and assign values to the .n and .l members within it. I then pass the ADDRESS OF that struct to the update() function. It takes in a pointer to the struct and using the struct pointer dereference operator (->) I then double the .n member and half the .l member.

 

When it returns to main() the .n member will be 24690 and the .l member will be 5D5F7D67.

 

I could have done the same thing like this:

int main(void) {
    str_t * ptr_struct;
    
    ptr_struct = (str_t *)malloc(sizeof(str_t));
    ptr_struct->n = 12345;
    ptr_struct->l = 0xBABEFACE;
    update(ptr_struct);
}

In this version I don't immediately instantiate a variable of type str_t. I create a POINTER to the structure type called ptr_struct. No memory has yet been allocated to hold .n and .l so next I malloc a block of memory (it'll be 6 bytes I guess) that will hold .n and .l

 

As I now have a pointer to struct not an actual struct I switch from using .n and .l to using ->n and ->l because I mean "the n/l member that is in the block of memory that 'ptr-struct' holds the address of". When I call update() I just pass it the pointer, I dropped the use of & (address of) because it's already the address of a block holding the 6 bytes where .n and .l live.

 

Now do the whole thing in C++:

class cppstruc {
    int n;
    long l;
};

void update(cppstruc *);

int main(void) {
    cppstruc * ptr_class;
    
    ptr_class = new cppstruc;
    ptr_class->n = 12345;
    ptr_class->l = 0xBABEFACE;
    update(ptr_class);
}

void update(cppstruc * ptr_to_class) {
    ptr_to_class->n *= 2;
    ptr_to_class->l /= 2;
}

Hope I got that right! (one of the local C++ gurus should correct me if wrong) but hopefully you can see how the C stuff develops towards the C++ version? And why -> is being used. Oh and for completeness I could do a version where new is not used:

int main(void) {
    cppstruc class_inst;
    
    class_inst.n = 12345;
    class_inst.l = 0xBABEFACE;
    update(&class_inst);
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
BaldurMar wrote: This example is way too complicated to explain linked lists and polymorphism. And then you go on to quote the classic shape/rectangle/triangle example?!?
 

 

The shape/rectangle example is an over-simplyfied version of basic polymorphism.

Which is good for teaching the theory/concept of polymorphism

 

Judging by his questions, he might have skipped a few chapters as you mentioned. So teaching polymorphism AND two different types of linked-lists, while introducing the concept of an linked lists  ALL at once seemed like a bit too much.

 

Software Engineering student @ Reykjavik University www.ru.is

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

All I am saying is that when I first read a C++ text and about the classic "shapes" example my first thought was "and what practical real world use would that have". I'm sure there must be some happy, half way medium between the two. In the world of AVr and embedded perhaps it would something like a generic output driver that has both LCD and UART classes derived from it or something like that?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You Freaks are GreatzZzZ!

Especially you Cliff!

"One's value is inherent; money is not inherent"

 

Chuck, you are in my heart!