Как создать счетчик для каждого объекта класса?

В коде есть класс School с полем quantity_of_pupils, которое далее будет увеличиваться на, +1 т.к. в школе прибавляется ученик. Класс Pupil наследуется из предыдущего и при создании объекта должен увеличиваться счетчик quantity_of_pupils у соответствующей школы, но при вызове print_quantity выводятся нули у обеих школ.

#include <iostream>
#include <string>

using namespace std;

class School
{
    protected:
        string name_of_school;
        unsigned quantity_of_pupils{0};
    public:
        School(string name_of_school): name_of_school(name_of_school){}
        void print()
        {
            cout << "school name: " << name_of_school << " ";
        }
        void print_quantity()
        {
            cout << "quantity of pupils: " << quantity_of_pupils << '\n';
        }
};

class Pupil : public School
{
    private:
        string name;
        unsigned age;
    public:
        Pupil(School name_of_school ,string name, unsigned age): School(name_of_school), name(name), age(age)
        {
            this->quantity_of_pupils += 1;
        }
        void print()
        {
            School::print();
            cout << "name: " << name << " age: " << age << '\n';
        }
};

int main()
{
    School bettany("St. Carolina");
    School marry("Borderland");

    Pupil lexus(bettany, "Alexey", 18);
    Pupil vlad(bettany, "Vlad", 20);
    lexus.print();
    bettany.print_quantity();
    marry.print_quantity();
    
    return 0;
}

Сделал ссылку и код заработал как необходимо

#include <iostream>
#include <string>

using namespace std;

class School
{
    protected:
        string name_of_school;
        unsigned quantity_of_pupils{0};
    public:
        School(string name_of_school): name_of_school(name_of_school){}
        void print()
        {
            cout << "school name: " << name_of_school << " ";
        }
        void print_quantity()
        {
            cout << "quantity of pupils: " << quantity_of_pupils << '\n';
        }
        void counter()
        {
            ++quantity_of_pupils;
        }
};

class Pupil : public School
{
    private:
        string name;
        unsigned age;
    public:
        Pupil(School &name_of_school ,string name, unsigned age): School(name_of_school), name(name), age(age)
        {
            name_of_school.counter();
        }
        void print()
        {
            School::print();
            cout << "name: " << name << " age: " << age << '\n';
        }
};

int main()
{
    School bettany("St. Carolina");
    School marry("Borderland");

    Pupil lexus(bettany, "Alexey", 18);
    Pupil vlad(bettany, "Vlad", 20);
    lexus.print();
    bettany.print_quantity();
    marry.print_quantity();
    
    return 0;
}

Ответы (1 шт):

Автор решения: NunOfIt

Почему у вас Ученик наследует Школу?

HolyBlackCat: Ученик не должен наследоваться от школы, потому что не является подвидом школы.

Если бы у вас было, например, наследование такого плана: Человек -> Ученик, т.е. все ученики являются людьми, то всё бы было правильно. Теперь давайте посмотрим, что у вас получается (School -> Pupil): все ученики являются школами...

Ваш код можно как-то так переформатировать, но лучше не мудрить и просто содать классы Pupil и School, и в School хранить vector, без указателей друг на друга...

Pupil.hpp

#ifndef PUPIL_HPP
#define PUPIL_HPP

#include <string>
#include <iostream>

class School;

class Pupil {
    int id;
    size_t age;
    std::string name;
    School* my_school;

    static int max_id;

public:
    Pupil();
    Pupil(const std::string&, size_t);

    int get_id() const;
    size_t get_age() const;
    School* get_school() const;
    std::string get_name() const;

    void change_age(size_t);
    bool set_school(School*);
    void change_name(const std::string&);

    explicit operator bool() const;
    bool operator==(const Pupil&) const;

    friend std::ostream& operator<<(std::ostream&, const Pupil&);
};

#endif

Pupil.cpp

#include "Pupil.hpp"
#include "School.hpp"

// ---------- //
// - public - //
// ---------- //

/* Static Variables */
int Pupil::max_id = -1;

/* Constructors */
Pupil::Pupil(): Pupil("", 0) {}
Pupil::Pupil(const std::string& name, size_t age): my_school(nullptr), name(name), age(age), id(++max_id) {}

/* Getters */
int Pupil::get_id() const { return id; }
size_t Pupil::get_age() const { return age; }
std::string Pupil::get_name() const { return name; }
School* Pupil::get_school() const { return my_school; }

/* Setters */
void Pupil::change_age(size_t new_age) { age = new_age; }
void Pupil::change_name(const std::string& new_name) { name = new_name; }

bool Pupil::set_school(School* my_school) {
    if(!my_school) { return false; }

    for(const Pupil& ppl: *my_school)
        if(ppl == *this) {
            this->my_school = my_school;
            return true;
        }
    return false;
}

/* Operators */
bool Pupil::operator==(const Pupil& other) const { return id == other.id; }
Pupil::operator bool() const { return my_school != nullptr && name != "" && age != 0; }

// ---------- //
// - friend - //
// ---------- //

std::ostream& operator<<(std::ostream& out, const Pupil& other) {
    out << "Pupil(";
    if(other) {
        out << "name: " << other.name << "; ";
        out << "age: " << other.age;
    }
    out << ')';
    return out;
}

School.hpp

#ifndef SCHOOL_HPP
#define SCHOOL_HPP

#include <vector>
#include "Pupil.hpp"

class School {
    std::string name;
    size_t number_of_pupils;
    std::vector<Pupil> pupils;

public:
    School();
    School(const std::string&);

    Pupil& at(size_t);
    size_t size() const;

    bool add_pupil(const Pupil&);

    std::vector<Pupil>::iterator end();
    std::vector<Pupil>::iterator begin();

    explicit operator bool() const;
    friend std::ostream& operator<<(std::ostream&, const School&);
};

#endif

School.cpp

#include "School.hpp"

// ---------- //
// - public - //
// ---------- //

/* Constructors */
School::School(): School("") {}
School::School(const std::string& name): name(name), number_of_pupils(0) {}

/* Getters */
Pupil& School::at(size_t i) { return pupils[i]; }
size_t School::size() const { return number_of_pupils; }

/* Main Class Fuctions */
bool School::add_pupil(const Pupil& ppl) {
    if(ppl.get_school()) { return false; }

    ++number_of_pupils;
    pupils.push_back(ppl);
    pupils.back().set_school(this);
    return true;
}

/* for-loop iterators */
std::vector<Pupil>::iterator School::end() { return pupils.end(); }
std::vector<Pupil>::iterator School::begin() { return pupils.begin(); }

/* Operators */
School::operator bool() const { return name != ""; }

// ---------- //
// - friend - //
// ---------- //

std::ostream& operator<<(std::ostream& out, const School& other) {
    out << "School{";
    if(other) {
        out << "name: " << other.name << "; ";

        out << "pupils: [";
        if(!other.pupils.empty()) {
            out << other.pupils[0];
            for(size_t i = 1; i < other.size(); ++i)
                out << ", " << other.pupils[i];
        }
        out << ']';
    }
    out << '}';
    return out;
}

main.cpp

#include "School.hpp"

int main() {
    School marry("Borderland");
    School bettany("St. Carolina");

    Pupil vlad("Vlad", 20);
    Pupil lexus("Alexey", 18);

    bettany.add_pupil(vlad);
    bettany.add_pupil(lexus);

    std::cout << marry << '\n';
    std::cout << bettany << '\n';
    return 0;
}

Вывод:

School{name: Borderland; pupils: []}
School{name: St. Carolina; pupils: [Pupil(name: Vlad; age: 20), Pupil(name: Alexey; age: 18)]}
→ Ссылка