2018-06-10 06:22:14

I'm currently working on a project in c++ which involves a game and hopefully decoupled modules/libraries to help make future games easier to produce. Additionally this is also a good way and reason for me to learn some programming patterns especially where they apply to games. I've been reading this book and finding it helpful and informative. I'm currently looking at this chapter on service locators. My code in my project is basically a copy of the code in the chapter on service locators but with names and implementation changed for my use-case; I'm not writing an audio locator. However, a missing symbols error forced me to separate the code further into a separate file and test the locator independently. The code is below:

// absTest.cpp

#include <iostream>
using namespace std;

class Base
{
public:
    ~Base() {}
    virtual void doSomething() = 0;
    };

    class SuperBase : public Base
    {
    public:
        virtual void doSomething() { cout << "i'm in SuperBase." << endl; }
    };

class Locator
{
private:
    static Base * pBase;

public:
    static void provide(Base * b) { pBase = b; }
    static Base * getBase() { return pBase; }
};

int main()
{
    SuperBase * sb_ptr = new SuperBase();
    Locator::provide(sb_ptr);

    Base * base_ptr = Locator::getBase();

    if (base_ptr != nullptr)
    {
        base_ptr->doSomething();
    }

    delete sb_ptr;

    return 0;
}

This results in the following error:

Kyles-MBP:2048 kyle$ g++ absTest.cpp
Undefined symbols for architecture x86_64:
  "Locator::pBase", referenced from:
      Locator::provide(Base*) in absTest-9b4565.o
      Locator::getBase() in absTest-9b4565.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

When compiling absTest.o by its-self and examining the it with nm I find this line:

Kyles-MBP:2048 kyle$ nm absTest.o | c++filt
...
                 U Locator::pBase
...

Meaning, pBase is undefined. I can provide the whole output, but that seemed a bit much for this already sprawling post. i'm not sure why its not making the assignment in the provide function. According to virtual abstract base classes you are able to assign a child class pointer of type SuperBase to a parent class pointer of type Base. If you are not familiar with this concept read chapter 12 of http://learncpp.com. I have found that site invaluable as a c++ reference.

Can anyone help solve this? Am I doing something wrong? is the service locator chapter wrong? Any help would be greatly appreciated. I am seriously at a loss.

I don’t believe in fighting unnecessarily.  But if something is worth fighting for, then its always a fight worth winning.
check me out on Twitter and on GitHub

2018-06-11 07:21:26

your problem is when you declare a member as static, you should declare it somewhere outside of the class
look at this:

// absTest.cpp

#include <iostream>
using namespace std;

class Base
{
public:
    ~Base() {}
    virtual void doSomething() = 0;
    };

    class SuperBase : public Base
    {
    public:
        virtual void doSomething() { cout << "i'm in SuperBase." << endl; }
    };

class Locator
{
private:
    static Base * pBase;

public:
    static void provide(Base * b) { pBase = b; }
    static Base * getBase() { return pBase; }
};

Base * Locator::pBase;

int main()
{
    SuperBase * sb_ptr = new SuperBase();
    Locator::provide(sb_ptr);

    Base * base_ptr = Locator::getBase();

    if (base_ptr != nullptr)
    {
        base_ptr->doSomething();
    }

    delete sb_ptr;

    return 0;
}

the undefined reference error happens because of this line
you can remove the static keyword from your code to resolve this, or declare it outside of the class as well