19

Before anyone calls me out for not looking at pre-existing questions, I have looked and realise that it is to do with declaration, but I still can't get it to work (might be something to do with me using vectors).

Manager.h:

#include "Flight.h"
#ifndef manager_h
#define manager_h

class Manager {
    static vector<Airport> airports;
    static vector<Flight> flights;
public:
    static void loadAirports();
    static void loadFlights();
    static Airport getAirport(string code);
    static vector<string> split(const string &s, vector<string> &elems);
};

#endif

Manager.cpp:

#include "Manager.h"

void Manager::loadAirports ()
{
    ifstream airportfile("airports.txt");
    string line;
    while (getline(airportfile, line))
    {
        vector<string> values;
        split(line, values);
        Airport airport (values[0], values[1], atoi(values[2].c_str()));
        airports.push_back(airport);
    }
}

void Manager::loadFlights ()
{
    ifstream flightfile("flights.txt");
    string line;
    while (getline(flightfile, line))
    {
        vector<string> values;
        split(line, values);
        Flight flight (getAirport(values[0]), getAirport(values[1]), atoi(values[2].c_str()), atoi(values[3].c_str()));
        flights.push_back(flight);
    }
    cout << flights.size() << endl;
}

Airport Manager::getAirport (string code)
{
    for (int i = 1; i < (int)airports.size(); i++)
    {
        if (airports[i].code == code)
            return airports[i];
    }
    throw exception();
}

vector<string> Manager::split(const string &s, vector<string> &elems) {
    stringstream ss(s);
    string item;
    while(getline(ss, item, ',')) {
        elems.push_back(item);
    }
    return elems;
}

It is throwing this error:

Manager.obj : error LNK2001: unresolved external symbol "private: static struct Vector Manager::airports" (?airports@Manager@@0U?$Vector@UAirport@@@@A)

Manager.obj : error LNK2001: unresolved external symbol "private: static struct Vector Manager::flights" (?flights@Manager@@0U?$Vector@UFlight@@@@A)

I realise i need to define the vectors, but how and where? I tried creating an empty constructor and then doing

Manager::Manager ()
{
    vector<string> flights;
    vector<string> airports;
}

But it just gave me a re-definition error.

oliverw92
  • 249
  • 1
  • 4
  • 10

3 Answers3

35

You have to define them in the .cpp file:

vector<string> Manager::flights;
vector<string> Manager::airports;
petert
  • 6,672
  • 3
  • 38
  • 46
Constantinius
  • 34,183
  • 8
  • 77
  • 85
24

In your .cpp file, you need to add the definitions of the static variables:

vector<Airport> Manager::airports;
vector<Flight> Manager::flights;

See Why are classes with static data members getting linker errors? from the C++ FAQ.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • Oh i didn't realise it had to go outside any kind of function or constructor. – oliverw92 May 26 '11 at 14:52
  • 1
    There is only one instance of a static so no constructor would be appropriate. It's a lot like the way you declare/define global variables. E.g. in header: `extern int count;` and in source file: `int count = 0;`. (Also note that `static` has various different meanings depending on where you find it.) – John McFarlane May 26 '11 at 14:57
5

Oli and Constantinius have answered your actual question, but I would recommend changing the class. As it stands it has only static members, so you can never create an object of this class. While this is legal C++, it is not in the spirit of C++ (Although there are other languages that do embrace this usage, such as C#)

All static members imply that you are trying for some kind of singleton, but there are more standard ways of enforcing the singleton-ness of a class.

Having said that - I advocate never building singleton-ness into a class. Rather write the class as a normal class, and provide a singleton wrapper. This also has the neat side effect of preventing the notorious static initialization order fiasco that your current code is liable to bump into.

So, something like (excluding the includes for brevity):

Manager.h

class Manager {
    vector<Airport> airports;
    vector<Flight> flights;
public:
    Manager();
    void loadAirports();
    void loadFlights();
    Airport getAirport(string code);
    vector<string> split(const string &s, vector<string> &elems);
};

Manager& GetManager();

Manager.cpp

Manager::Manager()
{
    loadAirports();
    loadFlights();
}

Manager& GetManager()
{
    static Manager manager;
    return manager;
}
Allison Lock
  • 2,375
  • 15
  • 17
  • Oh - and a seperate sidenote - if you use `std::set` or `std::map` instead of `std::vector`, you can avoid the linear search in `getAirport`. – Allison Lock May 26 '11 at 15:08