Mateusz Kowalski
Mateusz Kowalski

Reputation: 205

Vector of objects as a static class member

I have a following snippet of code:

class Person {
        std::string name_;
        std::string surname_;
        //static vector<???> tracer_;
    public:
        Person(std:: string name, std::string surname)
            : name_(name)
            , surname_(surname) {
                //something with tracer_
        }
        ~Person() {
            //something with tracer_
        }
        static void OutputPersons(std::ostream& out) {
            //print every element in tracer_
        }
};

class Worker {
        Person person_;
        std::string position_;
    public:
        Worker(const Person& person, std::string position)
            : person_(person)
            , position_(position) {
        }
};

What I want to achieve, is to print all instances of objects of class Person (name and surname, without position from class Worker) which exists at particular moment, so in example

Person s("aaa", "bbb");
Person t("ccc", "ddd");
{
    Person u("eee", "fff");
}
Worker w(Person("ggg","hhh"),"guard");
Person::OutputPersons(std::cout);

should print only

aaa bbb
ccc ddd
ggg hhh

as only these objects exists at the moment of calling Person::OutputPersons.

What I don't know is how to project class Person fields. As you see, I have been trying to make a static vector which should "trace" all objects of Person - with adding an element in constructor and removing in destructor. I only have a problem with type of elements in this vector, as I cannot put there any kind of pointer to class Person object.

EDIT:

As I get known it's legitimate to have a vector of Person*, I modified my code

class Person {
        std::string name_;
        std::string surname_;
        static std::vector<Person *> tracer_;
    public:
        Person(std:: string name, std::string surname)
            : name_(name)
            , surname_(surname) {
            tracer_.push_back(this);
        }

but I'm getting error "undefined reference to 'Person::tracer_'. What am I doing wrong?

Upvotes: 0

Views: 1289

Answers (1)

ApproachingDarknessFish
ApproachingDarknessFish

Reputation: 14313

To answer your comment, yes, it is perfectly valid to have pointers to a class a data members in your class.

However, there are a few modifications that you need to make to your code. For instance, in your setup the "ggg hhh" Person is not displayed because it is a temporary object whose destructor is called immediately after it is passed to the function. In order to catch this object, you have to add a user-defined copy-constructor to catch the object created in the function:

#include <iostream>
#include <algorithm>
#include <vector>

class Person 
{

private:

    std::string name_;
    std::string surname_;

    static std::vector<Person*> tracer_;

public:

    Person(std:: string name, std::string surname)
        : name_(name), 
          surname_(surname) 
    {
        tracer_.push_back(this);     //add the person
    }

    //copy constructor
    Person(const Person& p) : name_(p.name_), surname_(p.surname_)
    {
          tracer_.push_back(this);                  //add the person
    }

    ~Person() 
    {
       tracer_.erase(std::remove(tracer_.begin(), tracer_.end(), this), tracer_.end());                               //remove the person, little messy
    }

    static void OutputPersons(std::ostream& out) 
    {
        for (std::vector<Person*>::iterator it = tracer_.begin(); it != tracer_.end(); it++)              //iterate through vector and print all members
        {
            out << (*it)->name_ << ' ' << (*it)-> surname_ << '\n';
        }
    }
};

class Worker 
{
private:

    Person person_;
    std::string position_;

public:

    Worker(const Person& person, std::string position)
        : person_(person),
          position_(position) 
    {

    }
};

To answer your new question, you must define tracer_outside of your class like this:

std::vector<Person*> Person::tracer_;

That's just how static class variables work in C++.

With these modifications, the output is:

aaa bbb
ccc ddd
ggg hhh

Note: it would probably be a better design for Worker to inherit from Person rather than maintain a Person field.

Upvotes: 3

Related Questions