2

I have a class Student:

class Student {
private:
    unsigned int id;
    string name;
    vector<int> grades;
public:
    Student(unsigned int id, string name, vector<int> grades);;
    virtual ~Student() {}

    unsigned int getId() { return this->id; }
    string getName() { return this->name; }
    int getGradesAmount() { return this->grades.size(); }
    vector<int> getGrades() { return this->grades; }
    int getGrade(int i) { return this->grades[i]; }

    unsigned int getCoef()
    {
        unsigned int coef = 1;
        for (int i = 0; i < this->grades.size(); i++) { coef *= this->grades[i]; }
        return coef;
    }

    int getNameCoef() { return this->getName().size() % 2; }

    ostringstream getInfo()
    {
        ostringstream info;
        info << "ID: " << getId() << ".\n";
        info << "Name: " << getName() << ".\n";
        info << "Amount of grades: " << getGradesAmount() << ".\n";
        info << "Grades:";
        for (int i = 0; i < getGradesAmount(); i++)
            info << " " << getGrade(i);
        info << "\nProduct of grades: " << getCoef() << ".\n";
        info << "Is surname has odd number of symbols (0 = no / 1 = yes): " << getNameCoef() << ".\n";
        return info;
    }
};

Student::Student(unsigned int id, string name, vector<int> grades)
{
    this->id = id; this->name = name; this->grades = grades;
}

And a class Group:

class Group : public Student {
protected:
    int size = 0;
    vector<Student> group;
public:
    Group() : Student(getId(), getName(), getGrades()) {}

    void addStudent(Student student)
    {
        if (student.getNameCoef() == 1)
        {
            if (this->group.size() > 0)
            {
                for (int i = 0; i < this->group.size(); i++)
                {
                    if (student.getCoef() > group[i].getCoef())
                    {
                        this->group.insert(this->group.begin() + i, student);
                        this->size = this->size + 1;
                        return;
                    }
                }
            }

            cout << "\nAdded to start";
            this->group.push_back(student);
            this->size = this->size + 1;
        }
    }
};

In Group I'm trying to overload << to make a cout << group. So, I have added this into a Group:

friend ostream& operator<<(ostream& out, const Group& group) { // overloaded operator of output
        out << "\nThere are " << group.size << " students in the group.\n";
        for (int i = 0; i < group.size; i++)
        {
            out << "Student # " << i + 1 << ":\n";
            out << group[i].getInfo();
        }

        return out;
    }

But I have this error:

error C2676: binary '[': 'const Group' does not define this operator or a conversion to a type acceptable to the predefined operator

So, I googled for any [] overloaded operators for vector but didn't find anything that work for me. I also tried copying constructor, but it didn't helped me. How to use group[i].getInfo() ? Or maybe there are some oter ways to access this. So, group[i] must be Student object.

  • 2
    The `group` in your `operator<<` is not a `std::vector`. It's a `Group` object. Your `Group` class does not have an `operator[]` defined. Therefore, you can't use it on `group`. Since this function is a friend function, you can access private elements directly. Your vector is `group.group`. To access an element of the vector, you'd do `group.group[i]` – JohnFilleau Mar 30 '20 at 18:41
  • 1
    You're misusing inheritance here. `class Group : public Student` means that a `Group` is a type of `Student`, which obviously makes no sense. I suggest you review what inheritance is. Also, the `group` in your `operator<<` overload is not a vector. – eesiraed Mar 30 '20 at 18:44
  • It's also unusual that your `Group` inherits from `Student`. That means a `Group` *is* a `Student`. That doesn't make sense. It looks like `Group` could just get away with being a `std::vector` named `group` or `students` or something. You also don't need to track the `size` in `Group` since the `std::vector group` tracks its own size via `group.size();` – JohnFilleau Mar 30 '20 at 18:46
  • 2
    And, to add to the pile of problems, here, `getInfo()` is not a `const` class member. So, after squaring away all of the above issues, if you end up with a `const` object, you can't call its `getInfo()` method, anyway. And if `getInfo()` is changed to a `const` method, any method is calls itself also must be `const`. When you start learning about overloading operators, you'll need to quickly learn, and understand, what `const`-correctness means. – Sam Varshavchik Mar 30 '20 at 18:46
  • Copying `std::ostringstream` is not allowed, just like a `std::ostream`. That means you can't return it by value. –  Mar 30 '20 at 18:49
  • See https://stackoverflow.com/q/3442520/10957435 –  Mar 30 '20 at 18:51
  • Group inherits from Student because I can't create vector of objects Student otherwise. – Andrey Smirnov Mar 30 '20 at 19:07
  • "Group inherits from Student because I can't create vector of objects Student otherwise." then you're doing something wrong. You don't need to inherit from `std::vector` in order to have a member `std::vector`, so you don't need to inherit from `Student` to use `Student`. What error do you get when you remove the inheritance of `Student` from `Group`? – JohnFilleau Mar 30 '20 at 19:22
  • @JohnFilleau yes, you are right. I don't need inheritance here. – Andrey Smirnov Mar 30 '20 at 19:24

2 Answers2

1

It seems like you are confusing the group which is of type Group with its member, which is confusingly also called group.

Either you provide an Group::operator[] or you change your operator<< to

friend ostream& operator<<(ostream& out, const Group& group) { // overloaded operator of output
        auto& vect = group.group;
        out << "\nThere are " << vect.size() << " students in the group.\n";
        for (int i = 0; i < vect.size(); i++)
        {
            out << "Student # " << i + 1 << ":\n";
            out << vect[i].getInfo();
        }

        return out;
    }
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
1

There are several issues with your code (see comments), but the one you're asking about is because of this line:

out << group[i].getInfo();

As JohnFileau mentioned, group is a Group object, not a std::vector. If you want to access the std::vector group in the Group class, you will need group.group:

out << group.group[i].getInfo();

This will fix this issue, but it's only fair to warn you you will soon hit others. I recommend reading the comments on your question and figuring out how to fix them.


Something worth noting here is that part of the reason you're seeing this is you may not realize that operator<<() is not a member function of Group. That is, even if you define it inline like this:

class Group : public Student {
    //...
    friend ostream& operator<<(ostream& out, const Group& group) { // overloaded operator of output
            out << "\nThere are " << group.size << " students in the group.\n";
            for (int i = 0; i < group.size; i++)
            {
                out << "Student # " << i + 1 << ":\n";
                out << group[i].getInfo();
            }

            return out;
        }
};

It might look like it's a member of Group, but it's actually not. It is an external friend function. It is not actually a part of Group. That means you can't access the data members directly. For instance,

this->size

will fail because, again, it's not actually a member function.

If you want to access data members of Group, you need to access them via the instance you were passed (i.e., group:

group.size

Note that that means when you do something like group.size, you're actually getting data member Group::size, not the size() from std::vector.