类模板中的虚函数

Virtual function in class template

本文关键字:函数      更新时间:2023-10-16

我有一个名为Cache的模板类,它是字符串和对象的std::map的holder。

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;
}

和一个继承自Cache的模板类称为ResourceCalled,它基本上是相同的类,但具有不同的loadObject()方法。

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;
}

在我的程序中,我初始化ResourceCache<>并将T设置为一个名为Mesh的类,该类在其构造函数中有一个参数。现在当我尝试编译程序时,编译器报错:

错误C2512: 'Mesh':没有合适的默认构造函数可用

这就像它试图为Cache而不是ResourceCache构建代码。但是,当我在Cache::loadObject()之前省略了virtual关键字时,程序将编译。

为什么会发生这种情况?我学会了在继承时总是使用virtual关键字。

Cache<T>::loadObject()中,有

obj = new T();

如果T(在您的示例中是Mesh)没有默认构造函数,则该行不起作用。

Cache<T>::loadObject()virtual时,函数的基类实现和派生类实现都被实例化。

Cache<T>::loadObject()不是virtual时,只实例化该函数的派生类实现。函数的基类实现只有在显式使用时才会被实例化。

是的,它正在尝试构建缓存,因为这是你告诉编译器在某一点上要做的:

class ResourceCache : public Cache<T>

当T是实际类型时,编译器需要实例化Cache,其中包括方法Cache::loadObject,如果T没有默认构造函数,该方法将不编译。

你可以让基类的loadObject是纯虚拟的,然后从抽象类派生一个额外的类,实现你设置为默认的旧loadObject方法。