C ++:在基本模板类中调用派生的专用虚函数

时间:2014-04-01 10:59:04

标签: c++ templates polymorphism

假设我有以下模板类:

template<typename T>
class A
{
public:
    // Lots of functions...

    void someFunc(T obj)
    {
        // T must implement this function in order to be usable within class A.
        obj.interfaceFunc();
    }
};

这很好用,因为我将与模板类一起使用的对象实现 interfaceFunc()。

但是,如果我将指针传递给模板类,则编译失败,因为取消引用语法不正确。因为模板类包含很多其他函数,如果我可以帮助它,我不想复制/粘贴到另一个部分特化中,我已经改变了我的类定义如下:

template<typename T>
class A
{
public:
    // Lots of functions...

    virtual void virtualHelperFunction(T* obj)
    {
        // We should never be here in the base class.
        assert(false);
    }

    void someFunc(T obj)
    {
        // Call the virtual function.
        virtualHelperFunction(&obj);
    }
};

// Partial specialisation 1
template<typename T>
class B : public A<T>
{
public:
    // ...

    virtual void virtualHelperFunction(T* obj)
    {
        obj->interfaceFunc();
    }
};

// Partial specialisation 2
template<typename T*>
class B : public A<T*>
{
public:
    // ...

    virtual void virtualHelperFunction(T* obj)
    {
        obj->interfaceFunc();
    }
};

但是,当调用 virtualHelperFunction()时,在B的实例上,但是当在父A的 someFunc()函数内时,它会遇到断言错误。 :

B<SomeObject> instance;
instance.someFunc(SomeObject());  // Assertion failure.

我已经尝试过乱用函数指针来解决这个问题,但我对它们还是比较新的,而且非静态指针语法让我感到困惑。我假设可以定义一个指向 virtualHelperFunction()的成员指针,该指针设置为指向A的构造函数中的基类版本,但是然后在B的构造函数中将其覆盖以指向B的函数。如果是这样,是否有人能够演示正确的语法来执行此操作?

感谢。

编辑:如果需要上下文,模板类是一个八叉树节点,它存储类型为T的哈希表。所需的接口函数是对象可以返回一个边界框,以便递归插入功能取决于是否对象的边界与树节点的边界相交。

https://github.com/x6herbius/crowbar/blob/qt3d-experimental/Modules/Octree/inc/worldculltreenode.h https://github.com/x6herbius/crowbar/blob/qt3d-experimental/Modules/Octree/inc/worldculltreenode.tcc

4 个答案:

答案 0 :(得分:1)

这似乎太复杂了。如果你只需要一点点专门的话,为什么要专注于全班?你需要的只是一个小实用程序,如果它是一个指针,则说“取消引用它,否则不管它”。它看起来像这样:

template <typename T>
T& deref_if_pointer(T& t) { return t; }
template <typename T>
T& deref_if_pointer(T* t) { return *t; }

// ...
void someFunc(T obj) {
  deref_if_pointer(obj).interfaceFunc();
}

您也可以轻松地将deref_if_pointer扩展到各种智能指针;只是添加另一个重载。

答案 1 :(得分:0)

我不确定你想要完成什么,所以我不得不猜测。以下哪种方式不能满足您的问题?

class A
{
public:
    // Lots of functions...

    void someFunc(T* obj)
    {
        // T must implement this function in order to be usable within class A.
        obj->interfaceFunc();
    }

    void someFunc(T obj)
    {
        // T must implement this function in order to be usable within class A.
        obj.interfaceFunc();
    }
};

答案 2 :(得分:0)

如果你想这样做,那么你需要在第一个部分专业化中使用引用而不是指针:

template<typename T>
class A
{
public:
    // Lots of functions...

    virtual void virtualHelperFunction(T* obj)
    {
        // We should never be here in the base class.
        assert(false);
    }

    void someFunc(T obj)
    {
        // Call the virtual function.
        virtualHelperFunction(&obj);
    }
};

// Partial specialisation 1
template<typename T>
class B : public A<T>
{
public:
    // ...

    virtual void virtualHelperFunction(T& obj)
    {
        obj.interfaceFunc();
    }
};

// Partial specialisation 2
template<typename T*>
class B : public A<T*>
{
public:
    // ...

    virtual void virtualHelperFunction(T* obj)
    {
        obj->interfaceFunc();
    }
};

答案 3 :(得分:0)

您的代码无法编译。 template<typename T*>是非法的,并且您声称没有任何部分专业化。

这有效:

template<typename T>
class A
{
public:
    // Lots of functions...

    virtual void virtualHelperFunction(T* obj)
    {
        // We should never be here in the base class.
        assert(false);
    }

    void someFunc(T obj)
    {
        // Call the virtual function.
        virtualHelperFunction(&obj);
    }
};

// Unspecialized template
template<typename T>
class B : public A<T>
{
public:
    // ...

    virtual void virtualHelperFunction(T* obj)
    {
        obj->interfaceFunc();
    }
};

// Partial specialisation
template<typename T>
class B<T*> : public A<T*>
{
public:
    // ...

    virtual void virtualHelperFunction(T** obj)
    {
        (*obj)->interfaceFunc();
    }
};

int main() {
    B<SomeObject> instance1;
    instance1.someFunc(SomeObject());

    B<SomeObject*> instance2;
    SomeObject x;
    instance2.someFunc(&x);
}