Access a private data member within output opearator

closed account (L1bXjE8b)
I am working with this implementation file:
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
#include "section.h"
#include <list>
#include <iomanip>

using namespace std;

Section::Section ()
  : theCallNumber(0), //iterator.begin(0), 
  numStudents(0)
{
}

Section::Section (Course course, int callNumber)
  : theCourse(course), theCallNumber(callNumber), 
    //iterator.begin(0), 
  numStudents(0)
{
}

Section::Section (const Section& sect)
  : theCourse(sect.theCourse), theCallNumber(sect.theCallNumber), 
    //firstStudent(0), 
  numStudents(0) 
{
  list<Student>::const_iterator it;
  for (it = sect.begin(); it != sect.end(); ++it){
    students.push_back ( *it );
  }
}

Section& Section::operator= (const Section& sect) {
  if (this != &sect) {
  	   students.clear();
  }

  list<Student>::const_iterator it;
  for ( it = sect.begin(); it != sect.end(); ++it ) {
      students.push_back ( *it );
  }

  for ( it = sect.begin(); it != sect.end(); ++it ) {
     addStudent (*it); 
  }
return *this;
}

Section::~Section() {

    students.clear();
}

void Section::addStudent(Student s) {
      students.push_back ( s );
    }
}
*/
bool Section::operator== (const Section& right) const {
  return (theCourse == right.theCourse)
    && (theCallNumber == right.theCallNumber);
}

bool Section::operator< (const Section& right) const {
  if (theCourse < right.theCourse)
    return true;
  else if (theCourse == right.theCourse)
    return (theCallNumber < right.theCallNumber);
  else
    return false;
}

std::ostream& operator<< (std::ostream& out, const Section& section){
  out << setw(8) << left << section.getCourse() 
      << setw(6) << left << section.getCallNumber();
  out << ": " << section.getNumberOfStudents() << " students\n";

  list<Student>::const_iterator it;
  for ( it = section.begin(); it != section.end(); ++it ) {
      sort (students, students+section.getNumberOfStudents());
  }

  for (it = section.begin(); it != section.end(); ++it)
    out << "    " << *it << "\n";

  out << flush;
  return out;
}

And this header file:
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
#ifndef SECTION_H
#define SECTION_H

#include <list>
#include <string>
#include <iostream>


#include "course.h"
#include "student.h"

class Section
{
  Course theCourse;
  int theCallNumber;

  std::list<Student> students;
  int numStudents;


public:
  typedef std::list<Student>::iterator iterator;
  typedef std::list<Student>::const_iterator const_iterator;


  Section ();
  Section (Course course, int callNumber);

  Section (const Section&);
  Section& operator= (const Section&);
  ~Section();

  const Course& getCourse() const {return theCourse;}
  int getCallNumber() const       {return theCallNumber;}

  int getNumberOfStudents() const {return numStudents;}
  void addStudent(Student s);

  bool operator== (const Section& right) const;
  bool operator< (const Section& right) const;

  iterator begin();
  const_iterator begin() const;

  iterator end();
  const_iterator end() const;


};

std::istream& operator>> (std::istream& in, Section& section);
std::ostream& operator<< (std::ostream& out, const Section& section);

#endif 


As you may be able to see right off, I am having some trouble with the output operator(specifically, line 78). I need to have access to the std::list<Student>students so that I can sort it alphabetically. However, since students is private, I do not have access to it from within this output operator. What is the best way for me to be able to sort this list?
Last edited on
However, since students is private, I do not have access to it from within this output operator.

More importantly, an output operation has no business modifying the state of your object, and that is why a const reference to the Section object is used. Sort prior to output if you desire sorted output.
Last edited on
IMO the best solution is to sort the list before you try to "print" the Section. IMO this "print" function should really not modify the class.

By the way your iterators don't look correct, isn't section a single instance?

Is there a reason you chose to use std::list instead of std::vector?



closed account (L1bXjE8b)
Sort prior to output if you desire sorted output.

So, are you saying I should sort somewhere else--like in the constructor or addStudent?
Last edited on
So, are you saying I should sort somewhere else--like in the constructor or something?

Right before you do the output if you desire sorted output.

1
2
3
4
5
6
   Section section;
   // do stuff with section...

   // dome manipulating section, sort it for output
   std::sort(section.begin(), section.end());
   std::cout << section ; 


Or, if you require the data to always be sorted, use data structure that supports that (such as a set) or insert in order for every addition or sort after every addition.
Yes somewhere else, but probably not the constructor.

If you always want your students sorted, why are you not inserting the students into your list in sorted order in the first place?

closed account (L1bXjE8b)
Okay, so I would think that I should be able to use students.sort() to sort the list, but that is causing the linking to fail when I compile. I put the sort here:
1
2
3
4
5
void Section::addStudent(Student s) {
      students.push_back ( s );
      students.sort();
    }
}


I don't know about sorting the sections in the output operator.

What would be a better way to sort the students as I insert them instead of push_back()?
Last edited on
Did you look at any documentation for the std::list class?
http://www.cplusplus.com/reference/list/list/
http://www.cplusplus.com/reference/list/list/insert/

For list.sort()
http://www.cplusplus.com/reference/list/list/sort/

You'll probably need to either use the comp function/object or overload the proper operator for your class.
closed account (L1bXjE8b)

Did you look at any documentation for the std::list class?
http://www.cplusplus.com/reference/list/list/
http://www.cplusplus.com/reference/list/list/insert/

I did, but I thought I was doing it correctly with students.sort()

So, I've done a little modification:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Section::Section (const Section& sect)
  : theCourse(sect.theCourse), theCallNumber(sect.theCallNumber), 
    //firstStudent(0), 
  numStudents(0) 
{
  list<Student>::const_iterator it;
  for (it = sect.begin(); it != sect.end(); ++it){
    students.insert ( it, *it );
  }
}

Section& Section::operator= (const Section& sect) {
  if (this != &sect) {
  	   students.clear();
  }

  list<Student>::const_iterator it;
  for ( it = sect.begin(); it != sect.end(); ++it ) {
      students.insert ( it, *it );
  }

  for ( it = sect.begin(); it != sect.end(); ++it ) {
     addStudent (*it); 
  }


I think that should take care of ensuring that the students are added correctly, right? They should be alphabetized.
Last edited on
closed account (L1bXjE8b)
I am using insert() to add the students in order (I think), but I still have the problem with sorting the sections in the output operator:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
std::ostream& operator<< ( std::ostream& out, const Section& section ){
  // 1. print the section header
  out << setw(8) << left << section.getCourse() 
      << setw(6) << left << section.getCallNumber();
  out << ": " << section.getNumberOfStudents() << " students\n";

  list<Student>::const_iterator it;
  // 2. collect the students, sort, and print

  for (it = section.begin(); it != section.end(); ++it)
    section.sort ( it, section.getNumberOfStudents() );
    out << "    " << *it << "\n";

  out << flush;
  return out;
}


When I try to use section.sort(), I get an error saying there is no member named 'sort' in 'section'. How would I be able to sort these sections for output?
What are you trying to sort? Isn't section a single instance? You said you've already sorted the students, so what is left to sort?

As already been stated you shouldn't be altering (sorting) your class in an output function.

When I try to use section.sort(), I get an error saying there is no member named 'sort' in 'section'.

According to the class declaration in your OP, your class has no member function called 'sort'

cire gave you the answer here:
http://www.cplusplus.com/forum/general/192352/#msg926882

BTW, you're still trying to sort a const object. As others have said that's not going to work. How are you going to sort something without modifying it?

Last edited on
closed account (L1bXjE8b)
So I need to sort something that is passed to me as a constant reference. Where else can I sort it? The only other place I could think of that I have the section parameter modifiable is in the constructor. When I try to use:
1
2
3
4
5
6
Section::Section ()
  : theCallNumber(0)
  numStudents(0)
{
    sort ( section.begin(), section.end() );
}

that doesn't work either. Can someone help me with where to place this in the program as it is written?
Last edited on
cire gave you the answer here:
http://www.cplusplus.com/forum/general/192352/#msg926882

Unfortunately, that is not the answer. std::list iterators are not random access so they can't be used with std::sort.

The most obvious solution is to make the list being sorted an invariant of the class, in which case Section::AddStudent is the place for things to happen, whether it's calling sort after inserting an element or just inserting an element in the right place to begin with.

Either way, you need some way to compare students (and it's not clear from the code given whether that exists or not.)

Either:
1
2
3
4
5
void Section::addStudent(Student s) {
      students.push_back ( s );
      students.sort(comparison_func);
    }
}

where comparison_func is some user defined function for comparing one Student to another.

or

1
2
3
4
5
void Section::addStudent(Student s) {
      auto insertion_point = std::lower_bound(students.begin(), students.end(), s);
      students.insert(insertion_point, s);
    }
}

where there is an appropriate overload for operator<(const Student&, const Student&). Also note that there is an overload for lower_bound that takes 4 arguments where the last argument is a function object that designates the comparison function similar to the argument for list::sort.
Last edited on
Topic archived. No new replies allowed.