Pure virtual functions in Template class?

Discussion in 'C++' started by YellowMaple, Mar 24, 2007.

  1. YellowMaple

    YellowMaple Guest

    Is it possible to have pure virtual functions defined in a template
    class? I'm trying to do something like this:

    template <typename T>
    class Singleton
    {
    public:
    static T& getInstance(void)
    {
    if(m_pInstance == NULL)
    m_pInstance = new T;

    return *m_pInstance;
    }

    protected:
    Singleton() { }
    Singleton(const Singleton&);
    virtual ~Singleton() { }
    Singleton& operator=(const Singleton&);

    private:
    static T* m_pInstance;

    };

    template <typename T>
    T* Singleton<T>::m_pInstance = NULL;

    template <typename T>
    class Resigtry
    {
    public:
    ...
    virtual std::string getType() = 0;

    protected:
    ...
    virtual T* loadResource(std::fname) = 0;

    };

    class FontsRegistry
    : public Registry<Font>
    , public Singleton<FontsRegistry>
    {
    public:
    std::string getType() { return "FONT!!"; }

    protected:
    Font* loadResource(std::fname) { return new Font(); }

    friend class Singleton<FontsRegistry>;
    };

    but upon compilation i get:

    C:\mingw\include\c++\3.4.2\bits\stl_list.h:: undefined reference to
    `vtable for FontRegistry'
    :C:\mingw\include\c++\3.4.2\bits\stl_list.h:: undefined reference to
    `vtable for FontRegistry'
    :: === Build finished: 2 errors, 2 warnings ===

    I want to have a bunch of classes that handle external resources (i.e.
    FontsRegistry for fonts, MeshRegistry for meshes, etc.) but to avoid
    having to cut/paste code a whole bunch of times, I wanted to make an
    abstract class Registry, that they can derive from.
    YellowMaple, Mar 24, 2007
    #1
    1. Advertising

  2. YellowMaple wrote:
    > Is it possible to have pure virtual functions defined in a template
    > class? I'm trying to do something like this:
    >

    .... non compilable code removed
    >
    > but upon compilation i get:
    >
    > C:\mingw\include\c++\3.4.2\bits\stl_list.h:: undefined reference to
    > `vtable for FontRegistry'
    > :C:\mingw\include\c++\3.4.2\bits\stl_list.h:: undefined reference to
    > `vtable for FontRegistry'
    > :: === Build finished: 2 errors, 2 warnings ===
    >
    > I want to have a bunch of classes that handle external resources (i.e.
    > FontsRegistry for fonts, MeshRegistry for meshes, etc.) but to avoid
    > having to cut/paste code a whole bunch of times, I wanted to make an
    > abstract class Registry, that they can derive from.
    >


    The code below compiles and links - your problem is elsewhere. To make
    it easier next time, try to make the code you post compile and
    demonstrate the issue you observe.

    #include <string>

    template <typename T>
    class Singleton
    {
    public:
    static T& getInstance(void)
    {
    if(m_pInstance == NULL)
    m_pInstance = new T;

    return *m_pInstance;
    }

    protected:
    Singleton() { }
    Singleton(const Singleton&);
    virtual ~Singleton() { }
    Singleton& operator=(const Singleton&);

    private:
    static T* m_pInstance;

    };

    template <typename T>
    T* Singleton<T>::m_pInstance = NULL;

    template <typename T>
    class Registry
    {
    public:
    // ...
    virtual std::string getType() = 0;

    protected:
    // ...
    virtual T* loadResource(std::string) = 0;

    };

    class Font {};

    class FontsRegistry
    : public Registry<Font>
    , public Singleton<FontsRegistry>
    {
    public:
    std::string getType() { return "FONT!!"; }

    protected:
    Font* loadResource(std::string) { return new Font(); }

    friend class Singleton<FontsRegistry>;
    };

    FontsRegistry x;

    int main()
    {
    }
    Gianni Mariani, Mar 24, 2007
    #2
    1. Advertising

  3. YellowMaple

    YellowMaple Guest

    Sorry, for the sake of brevity I excluded most of the code. Here is
    an accurate representation:

    in Singleton.h:

    #ifndef __SINGLETON_H
    #define __SINGLETON_H

    template <typename T>
    class Singleton
    {
    public:
    static T& getInstance(void)
    {
    if(m_pInstance == NULL)
    m_pInstance = new T;

    return *m_pInstance;
    }

    protected:
    Singleton() { }
    Singleton(const Singleton&);
    virtual ~Singleton() { }
    Singleton& operator=(const Singleton&);

    private:
    static T* m_pInstance;

    };

    template <typename T>
    T* Singleton<T>::m_pInstance = NULL;

    #endif

    In Registry.h

    #ifndef __REGISTRY_H
    #define __REGISTRY_H

    #include <map>
    #include <string>
    #include <algorithm>

    #include <Design/Subject.h>
    #include <Utility/Globals.h>
    #include <Design/Singleton.h>

    struct delete_ptr
    {
    template <typename T>
    void operator() (const T& obj) const
    {
    delete obj.second;
    }
    };

    template <typename ResourceType>
    class Registry
    : public Subject
    {
    public:
    typedef std::string resource_type;

    ResourceType* create(std::string);
    void clear();
    bool empty() { return m_list.empty(); }

    virtual resource_type getType() = 0;

    protected:
    Registry() { }
    virtual ~Registry() { clear(); }
    Registry(const Registry&);
    Registry& operator=(const Registry&);

    virtual ResourceType* loadResource(std::string) = 0;

    typedef std::map<resource_type, ResourceType*> registry_list;
    registry_list m_list;

    };

    template <typename ResourceType>
    ResourceType* Registry<ResourceType>::create(std::string name)
    {
    return NULL;
    }

    template <typename ResourceType>
    void Registry<ResourceType>::clear()
    {
    notifyAll();
    for_each(m_list.begin(), m_list.end(), delete_ptr());
    m_list.clear();
    }

    #endif

    and finally, FontRegistry.h:

    #ifndef __FONTREGISTRY_H
    #define __FONTREGISTRY_H

    #include <string>

    #include <FTGLPixmapFont.h>

    #include <Resources/Registry.h>

    #define FONT_TYPE ".ttf"

    class FontRegistry
    : public Registry<FTFont>
    , public Singleton<FontRegistry>
    {
    public:
    ~FontRegistry();

    resource_type getType() { return FONT_TYPE; }

    protected:
    FTFont* loadResource(std::string) { return NULL; }

    private:
    FontRegistry() { }
    FontRegistry(const FontRegistry&);
    FontRegistry operator=(const FontRegistry&);

    typedef FTGLPixmapFont FontType;

    friend class Singleton<FontRegistry>;

    };

    #endif

    The font registry is used like so:

    FTFont* ftgl_font = FontRegistry::getInstance().create(font);

    Compilation in Code::Blocks with the MinGW compiler gives these
    errors:

    C:\MinGW\bin\..\lib\gcc\mingw32\3.4.2\..\..\..\..\include\c++
    \3.4.2\backward\backward_warning.h:32: warning: #warning This file
    includes at least one deprecated or antiquated header. Please consider
    using one of the 32 headers found in section 17.4.1.2 of the C++
    standard. Examples include substituting the <X> header for the <X.h>
    header for C++ includes, or <iostream> instead of the deprecated
    header <iostream.h>. To disable this warning use -Wno-deprecated.
    ...\..\Framework_01\src\System\Console.cc:44: warning: unused variable
    'width'
    C:\mingw\include\c++\3.4.2\bits\stl_list.h:: undefined reference to
    `vtable for FontRegistry'
    :C:\mingw\include\c++\3.4.2\bits\stl_list.h:: undefined reference to
    `vtable for FontRegistry'
    :: === Build finished: 2 errors, 2 warnings ===
    YellowMaple, Mar 24, 2007
    #3
  4. YellowMaple wrote:
    > Sorry, for the sake of brevity I excluded most of the code. Here is
    > an accurate representation:
    >

    ......
    >
    > class FontRegistry
    > : public Registry<FTFont>
    > , public Singleton<FontRegistry>
    > {
    > public:
    > ~FontRegistry();
    >

    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    Your problem is here. This is a virtual destructor and you have not
    implemented it.

    Please take a few more minutes to make the code compilable (cut-n-paste)
    so that the code you give shows the error without others having to guess
    what are the other errors about.

    This is the code I ended up with, I'm not sure it truly represents your
    problem.

    Another pointer, avoid #defines like the one you use for FONT_TYPE.

    //in Singleton.h:

    #include <string>

    #ifndef __SINGLETON_H
    #define __SINGLETON_H

    template <typename T>
    class Singleton
    {
    public:
    static T& getInstance(void)
    {
    if(m_pInstance == NULL)
    m_pInstance = new T;

    return *m_pInstance;
    }

    protected:
    Singleton() { }
    Singleton(const Singleton&);
    virtual ~Singleton() { }
    Singleton& operator=(const Singleton&);

    private:
    static T* m_pInstance;

    };

    template <typename T>
    T* Singleton<T>::m_pInstance = NULL;

    #endif

    //In Registry.h

    #ifndef __REGISTRY_H
    #define __REGISTRY_H

    #include <map>
    #include <string>
    #include <algorithm>

    //#include <Design/Subject.h>
    //#include <Utility/Globals.h>
    //#include <Design/Singleton.h>

    struct delete_ptr
    {
    template <typename T>
    void operator() (const T& obj) const
    {
    delete obj.second;
    }
    };

    class Subject {};

    template <typename ResourceType>
    class Registry
    : public Subject
    {
    public:
    typedef std::string resource_type;

    ResourceType* create(std::string);
    void clear();
    bool empty() { return m_list.empty(); }

    virtual resource_type getType() = 0;

    protected:
    Registry() { }
    virtual ~Registry() { clear(); }
    Registry(const Registry&);
    Registry& operator=(const Registry&);

    virtual ResourceType* loadResource(std::string) = 0;

    typedef std::map<resource_type, ResourceType*> registry_list;
    registry_list m_list;

    };

    template <typename ResourceType>
    ResourceType* Registry<ResourceType>::create(std::string name)
    {
    return NULL;
    }

    template <typename ResourceType>
    void Registry<ResourceType>::clear()
    {
    //notifyAll();
    //for_each(m_list.begin(), m_list.end(), delete_ptr());
    //m_list.clear();
    }

    #endif

    //and finally, FontRegistry.h:

    #ifndef __FONTREGISTRY_H
    #define __FONTREGISTRY_H

    #include <string>

    //#include <FTGLPixmapFont.h>

    //#include <Resources/Registry.h>

    #define FONT_TYPE ".ttf"

    class FTFont {};

    class FontRegistry
    : public Registry<FTFont>
    , public Singleton<FontRegistry>
    {
    public:
    ~FontRegistry() {};

    resource_type getType() { return FONT_TYPE; }

    protected:
    FTFont* loadResource(std::string) { return NULL; }

    private:
    FontRegistry() { }
    FontRegistry(const FontRegistry&);
    FontRegistry operator=(const FontRegistry&);

    class FTGLPixmapFont {};

    typedef FTGLPixmapFont FontType;

    friend class Singleton<FontRegistry>;

    };

    #endif

    int main()
    {
    FTFont* ftgl_font = FontRegistry::getInstance().create( "" );
    }
    Gianni Mariani, Mar 24, 2007
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Todd Aspeotis
    Replies:
    3
    Views:
    458
    Kanenas
    May 30, 2005
  2. John Goche
    Replies:
    10
    Views:
    736
    Marcus Kwok
    Dec 8, 2006
  3. Arne Schmitz
    Replies:
    4
    Views:
    428
    Daniel Albuschat
    Jan 17, 2007
  4. Replies:
    2
    Views:
    555
  5. Martin
    Replies:
    5
    Views:
    468
    Felix Palmen
    Aug 26, 2010
Loading...

Share This Page