How to access class objects within a linked list?

I created a doubly linked list which is able to successfully store a list of class objects, however I am having trouble accessing that linked list.

If I set the following to public in my sleepList class: (side stepping getters and setters for now)

sleepNode<Type> *head, *tail;

and use this in main.cpp :

1
2
3
4
sleepList<typedef> list; // a sleepRecord type
sleepRecord record;
record.startTime.setHour(1);
cout << record.startTime.getHour() << endl;


The output is simply 1 (as expected since that's the integer I am storing).

If I add this:

1
2
list.insertLast(record);
cout << list.head;


It gives a memory address of course, since that's just a pointer to the class object and it wouldn't be meaningful anyway since it's really a variable within the node that I want.

What I'd like to do is maybe take the entire object pointed to by the node and work with it directly. Being able to read from and write to the variables within the node would be very useful. Of course, if I could just overwrite an object outside the list with the node that would still suit my current needs.

However, this:

 
  record = list.head;


Doesn't work, even though list.head should contain an object of the same type as record. So how would I go about doing this?

I can post all the code involved in the program, but last time I did that no one answered at all so this time I guess I'll just wait and see if someone asks for it.
Last edited on
Quick Quiz:
What is in the bar?
Foo *bar;

You state: "should contain an object of type" Foo.

That is not true. The bar is a pointer. The bar has an address.

If you want to reach an object pointed to by a pointer, then you have to dereference the pointer.

Lets say that Foo's have a button. Foo::button. When you do have a Foo object, you access member with the . operator:
1
2
Foo gaz;
gaz.button


The bar is a pointer. Dereference and then access member:
(*bar).button
or use the other member access operator:
bar->button
sleepList<typedef> list;
The above line doesn't make any sense to me. You can't use the keyword typedef as a typename in a template instantiation.

 
record = list.head;

Doesn't work, even though list.head should contain an object of the same type as record.

No, those are NOT the same type. record is an object of type sleepRecord. You haven't shown the declaration for sleepList<>, however, I assuming that list.head is a pointer to to an object, not an actual object.

If you want to deal with outputting record as an entire object, you could always overload sleepRecord's << operator.
 
friend ostream & operator << (ostream & os, const sleepRecord & rec);



Last edited on
The bar is a pointer. The bar has an address.


I misspoke. I did afterwards say that I wanted to access the object pointed to by a node. I also made clear that if I simply did this:

cout << list.head;

It would show a memory address, so I do understand that we're dealing with pointers here. and actually, I did try a few variations of what you suggested already, but they didn't quite work right.

So if I use something more similar to your example:

cout << (*list).head;

It wouldn't mean anything because the head itself is (pointing to) an object that stores information.This, however, doesn't work either:

cout << (*list).head.startTime.getHour();

You see, the problem I am having is that once I am looking at a node I can't seem to get inside of it.

Similarly, this doesn't work either because it's an illegal indirection:

record << (*list).head;

The above line doesn't make any sense to me.


This:

sleepList<typedef> list;

works the same as

sleepList<sleepRecord> list;

I have no problem using either for creating the list, but if it helps you to understand the problem I am having than we'll just go with that for now.

If you want to deal with outputting record as an entire object, you could always overload sleepRecord's << operator.


I just want to be able to access a specific method within the objects stored in the linked list.

You haven't shown the declaration


Like I said, I can show whatever is needed, but last time I showed everything after listing a problem I was having it was clearly too much for anyone to bother reading. That being said, if it helps, here is one of the header files:

linkedlist.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
36
37
38
39
40
41
42
43
44
45
46
47
48
#pragma once
#include "time.h"
#include "include.h"

template <class Type>
struct sleepNode
{
    sleepRecord data;
    sleepNode *next;
    sleepNode *prev;
};

template <class Type>
class sleepList
{
private:
    
    int count = 0; //keeping track of list length
public:
    sleepNode<Type> *head, *tail; //TODO: move to private after making getters/setters

    sleepList()
    {
        head = nullptr;
        tail = nullptr;
    }

    void insertLast(sleepRecord record) 
    {
        if (head == nullptr)
        {
            this->head = new sleepNode<Type>;
            this->tail = new sleepNode<Type>;
        }
        else
        {
            this->tail = new sleepNode<Type>;
        }

        this->count++;
    }

    ~sleepList() //destructor
    {

    }
};


and this is the class storing the records to be added as nodes:

1
2
3
4
5
6
7
8
9
10
class sleepRecord
{
public: 
    Time startTime;
    Time endTime;
    Date startDate;
    Date endDate;
    int playerNumber;   // expect 0 - 99
    string playerName;  // Last name given so may not be unique
};


In the example I provided I tested the object by using a setter to store an integer in hour and then a getter to print that integer onto the screen. I am just trying to do the exact same thing, but after it is part of a linked list.

I had hoped that showing the usage of storing to and reading from the record would be sufficient, but since it doesn't seem to be here's the code referenced in the sleepRecord header. I can show the .cpp file as well if it's needed, or anything more:

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
class Time
{
protected:
    int hour;
    int min;
    int sec;
public:
    Time();
    Time(int hour, int min, int sec);

    long diff(const Time time) const;            // return difference in time in sec
    void diff(const Time start, const Time end); // compute difference in time

    //Setters:
    void setTime(int hour, int min, int sec);
    void setHour(int hour);
    void setMinute(int min);
    void setSecond(int sec);

    //Getters:
    int getHour() const;
    int getMinute() const;
    int getSecond() const;

    //Copy constructor
    Time(const Time &time);

    string toString() const;
    void addTime(const Time time);
    void addTime(const long sec);

    //Destructor
    ~Time();

private:
    void normalize();

};

class Date
{
public:
    int	day;
    int	month;
    int	year;
    string	toString();

    //Destructor
    ~Date();
};


Last edited on
Line 5-6,20: Why is sleepNode a template? You say it takes type Type, but Type is not used in the template. Perhaps you meant line 8 as Type data;.

Lines 34-49: You pass record in as an argument, but nowhere do you store record.

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
#pragma once
//  #include "time.h"
//  #include "include.h"
#include <string>

class sleepRecord
{
public: 
    //  Time startTime;         //  Commented out because I don't have the headers
    //  Time endTime;
    //  Date startDate;
    //  Date endDate;
    int playerNumber;   // expect 0 - 99
    std::string playerName;  // Last name given so may not be unique
};

struct sleepNode
{   sleepRecord data;
    sleepNode *next;
    sleepNode *prev;
};

template <class SN>     //  Renames the TYPE argument for clarity
class sleepList
{   int count;  
    SN   *head, 
         *tail; 
public:   
    sleepList()
    {   head = nullptr;
        tail = nullptr;
        count = 0;
    }

    const SN * getHead() const   //  Note that we're returning a pointer
    {   return head;
    }

    void insertLast (sleepRecord record) 
    {   SN * node = new SN;    

        node->data = record;
        if (head == nullptr)
        {   head = node; 
            tail = node; 
        }
        else
        {   node->prev = tail;      //  Node needs to point back
            node->next = nullptr;   //  No forward pointer
            tail->next = node;      //  Old tail points to new node            
        }
        count++;
    }

    ~sleepList() 
    {   //  Need to walk the list and delete all the elements here
    }
};



You pass record in as an argument, but nowhere do you store record.

That occurs in main.cpp and I already provided that information with the first post. It happens through insertLast though.

1
2
3
4
5
sleepList<sleepRecord> list;
sleepRecord record;
record.startTime.setHour(1);
cout << record.startTime.getHour() << endl;
list.insertLast(record);


I do find it curious that you put this:

SN * node = new SN;

Where I originally had this:

sleepNode<Type> * new sleepNode<Type>(sleepRecord record);

but removed because it gave me an error. That seems to be what I was missing there. No problems with it.

Here, I think it will help if you can see the entire program all put together. I just put it on my google drive for the time being. It compiles and runs with no errors, and I have a few things tested and displayed and made sure to remove any executables from debug folders:

https://drive.google.com/open?id=1L9KM074uCDh0NC8PMwa0hghd8y83XESS

It can be opened in visual studios, or a new project can import the files in any IDE.

This is actually a rewrite of a previous program I wrote that used a 2D array instead of linked lists, and I have much more code to write then I get through this hurdle where I'd use my old program as a model for this one. After I write an iterator for this of course. Much of what I am doing right now is just testing small pieces of code.
Last edited on
It happens through insertLast though.

No. Your insertLast never stores record.


OK, so what am I missing?
void insertLast (sleepRecord record);

the content of the variable/argument "record" is not used anywhere in that function, dont you want to assign its value/data to the newly allocated node ?
I want to assign the record to the node after assigning values to the record. Then I want to traverse the list and read from the records.

The program will basically accept multiple data files, reading a single line into an object (after checking the list to make sure a number hasn't been used before, to avoid repetitive data) and then put that "line" into a node and then continue into all lines have been read.

Here's what I am presently working on to get the data ready to go into the list:

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
        while (getline(*inFile, line))
        {
            int dayStart;       // Expect 1 - 31
            int monthStart;     // Expect 1 - 12
            int yearStart;      // Expect 2017 or larger
            int hourStart;      // expect 0 - 23
            int minuteStart;    // expect 0 - 59
            int secondStart;    // expect 0 - 59
            int dayEnd;         // expect 1 - 31
            int monthEnd;       // Expect 1 - 12
            int yearEnd;        // Expect 2017 or larger
            int hourEnd;        // Expext 0 - 23
            int minuteEnd;      // Expect 0 - 59
            int secondEnd;      // expect 0 - 59

            int playerNumber;   // expect 0 - 99
            string playerName;

            string value;
            stringstream linestream(line);

            //// used for testing:
            // cout << line << endl;

            getline(linestream, value, ',');
            stringstream temp1(value);
            temp1 >> dayStart;

            getline(linestream, value, ',');
            stringstream temp2(value);
            temp2 >> monthStart;

            getline(linestream, value, ',');
            stringstream temp3(value);
            temp3 >> yearStart;
            
            getline(linestream, value, ',');
            stringstream temp4(value);
            temp4 >> hourStart;

            getline(linestream, value, ',');
            stringstream temp5(value);
            temp5 >> minuteStart;

            getline(linestream, value, ',');
            stringstream temp6(value);
            temp6 >> secondStart;

            getline(linestream, value, ',');
            stringstream temp7(value);
            temp7 >> dayEnd;

            getline(linestream, value, ',');
            stringstream temp8(value);
            temp8 >> monthEnd;

            getline(linestream, value, ',');
            stringstream temp9(value);
            temp9 >> yearEnd;

            getline(linestream, value, ',');
            stringstream temp10(value);
            temp10 >> hourEnd;

            getline(linestream, value, ',');
            stringstream temp11(value);
            temp11 >> minuteEnd;

            getline(linestream, value, ',');
            stringstream temp12(value);
            temp12 >> secondEnd;

            getline(linestream, value, ',');
            stringstream temp13(value);
            temp13 >> playerNumber;

            getline(linestream, playerName, ',');

            record.startTime.setTime(hourStart, minuteStart, secondStart);
            record.endTime.setTime(hourEnd, minuteEnd, secondEnd);

            record.startDate.day = dayStart;
            record.startDate.month = monthStart;
            record.startDate.year = yearStart;

            record.endDate.day = dayEnd;
            record.endDate.day = monthEnd;
            record.endDate.day = yearEnd;

            record.playerNumber = playerNumber;
            record.playerName = playerName;

            //// used for testing:
//            cout << record.startTime.getHour();

        }


In order to finish that I need to be able to put the object into the list if I am not already doing that correctly and to be able to read methods from within the nodes within the list.

EDIT: The above code puts all values from a single line from a text file into the correct variables within a sleepRecord object. All I need help with is the part I asked to begin with. Does anyone actually know?

It just seems like no one here wants to answer direct and simple questions. It shouldn't even be necessary to have to upload an entire project with all source code for a work in progress over a single simple question, but so far the only answers are essentially to tell me things don't work that do work (typedef), to tell me to rename things that don't even matter, or to tell me how to access class members in exactly the same way I was already doing it.

All that's needed is the syntax used in my program. If an object is stored within a node, how exactly am I supposed to read the data within the object? If there is something else I am not doing right, well, that's still a problem, but I actually prefer to do as much of my own work as possible. I only need help with one little thing and I don't want to otherwise be given too much information.
Last edited on
Using a data file with 9 entries, and the following code, this is the resulting output:

Size of core record: 80 bytes.
Size of sleep record list: 12 byte(s).

No file name given.
list started!
node added!
node added!
node added!
node added!
node added!
node added!
node added!
node added!
Press any key to continue . . .


So the method is being used, it appears to be adding notes in the correct manner, I just need help reading them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    void insertLast(sleepRecord record) 
    {
        sleepNode<Type> * newNode;
        newNode = new sleepNode<Type>;
        newNode->data = record;
        
        if (head == nullptr)
        {
            cout << "list started!" << endl;
            this->head = new sleepNode<Type>;
            this->tail = new sleepNode<Type>;
        }
        else
        {
            cout << "node added!" << endl;
            this->tail = new sleepNode<Type>;
        }

        this->count++;
    }
Last edited on
Your insertLast() is seriously different from the AbstractAnion version. You create surplus objects and neglect to maintain links.


Another matter:
Your sleepList is a template that can store various data types.
Why can the insertLast() take exactly one type of data in, the sleepRecord?
Registered users can post here. Sign in or register to post.