McLovin
McLovin

Reputation: 3417

Virtual function in class template

I have this template class called Cache, which is a holder for an std::map of strings and objects.

template<class T>
class Cache
{
public:
    Cache() {}
    virtual ~Cache();

    virtual T* loadObject(const char *file);
    virtual bool removeObject(const char *file);
    virtual void removeAllObjects();

    virtual unsigned int getNumObjects() const;
    virtual T* getObject(const char *file);

protected:
    typedef std::shared_ptr<T> t_ptr;

    std::unordered_map<std::string, t_ptr> _objects; //file, shared ptr of object
};

template<class T>
T* Cache<T>::loadObject(const char *file)
{
    //if object exists
    T *obj = getObject(file);
    if(obj)
        return obj;

    obj = new T();

    if(obj)
        return _objects.insert(std::make_pair(file,t_ptr(obj))).first->second.get();
    else
        return nullptr;
}

and a template class that inherits from Cache is called ResourceCalled, which is basically the same class but with a different loadObject() method.

template<class T>
class ResourceCache : public Cache<T>
{
public:
    ResourceCache(ResourceLoader<T> *resourceLoader) : _resourceLoader(resourceLoader)
    {}

    virtual T* loadObject(const char *file);

private:
    ResourceLoader<T> *_resourceLoader;
};

template<class T>
T* ResourceCache<T>::loadObject(const char *file)
{
    //if object exists
    T *obj = getObject(file);
    if(obj)
        return obj;

    obj = _resourceLoader->load(file);
    if(obj)
        return _objects.insert(std::make_pair(file,t_ptr(obj))).first->second.get();
    else
        return nullptr;
}

In my program, I initiate ResourceCache<> with T set to a class called Mesh, that has a parameter in its constructor. Now when I try to compile my program, the compiler complains:

error C2512: 'Mesh' : no appropriate default constructor available

It's like it's trying to build a code for Cache and not ResourceCache. But when I omit the virtual keyword before Cache::loadObject(), the program compiles.

Why does this happen? I learned to always use the virtual keyword when doing inheritance.

Upvotes: 0

Views: 145

Answers (2)

R Sahu
R Sahu

Reputation: 206577

In Cache<T>::loadObject(), you have the line

obj = new T();

That line doesn't work if T, Mesh in your case, does not have a default constructor.

When Cache<T>::loadObject() is virtual, both the base class implementation as well as the derived class implementation of the function are instantiated.

When Cache<T>::loadObject() is not virtual, only the derived class implementation of the function is instantiated. The base class implementation of the function will be instantiated only if it is used explicitly.

Upvotes: 2

A Hernandez
A Hernandez

Reputation: 484

Yes, it is trying to build Cache because that is what you are telling the compiler to do at one point:

class ResourceCache : public Cache<T>

At the point where T is an actual type, the compiler needs to instantiate Cache, and that includes the method Cache::loadObject, which does not compile if T does not have a default constructor.

You could make the base class have the loadObject be pure virtual, and then have an extra class deriving from the abstract class that implements the old loadObject method that you were setting as default.

Upvotes: 1

Related Questions