类模板中的虚函数,没有模板类型作为参数/返回值

时间:2014-04-08 20:45:08

标签: c++ class templates virtual

据我所知,由于vtable的大小不确定,因此不允许/可能使用模板化的虚函数。

另一方面,似乎允许不使用模板类型的类模板中的虚函数,对吧?

虚拟函数如何不使用模板类型作为参数或返回类型,但是对模板类型的数据起作用?这是有效的C ++吗?

我已经做了一些测试,似乎有效。

我的代码如下:

(注意:出于可读性的原因,这只是基本结构,而不是实际代码)。

template<typename T>
class Base {
public:
    virtual bool compare(void) {
        // Basic implementation
        return ((value1 + value2) < value3);
    }
protected:
    T value1, value2, value3;
}


/**
 * Derived from Base<ComplexClass> where
 * ComplexClass is a Class providing
 * a int Value through .getInt()
**/
class Derived : Base<ComplexClass> {
    bool compare(void) {
        return ((value1.getInt() + value2.getInt()) < value3.getInt());
    }
}

main {
    Base<int> *intBase = new Base<int>();
    Base<double> *doubleBase = new Base<double>();
    Base<ComplexClass> *complexBase = new Derived();

    intBase->compare(); // Should call base function
    doubleBase->compare(); // Should also call base function
    complexBase->compare(); // Should call the compare function of Derived
}

据我所知,这就像我除外。这只是一个幸运的巧合,还是这种有效/优秀的C ++风格?

如果它有效,有人可以解释一下里面发生了什么,以及为什么有些人说从类模板派生并使用类模板中的虚函数是禁止/不良做法?

提前谢谢!

PS:我知道模板专业化可以做类似的事情,但我想知道这种方式是否也可能。

2 个答案:

答案 0 :(得分:1)

据我所知,由于vtable的大小不确定,因此不允许/可能使用模板化虚拟函数。

A 您可以在课程模板中使用虚拟功能。

编译和链接的示例代码:

 template <typename T>
 struct Base
 {
    virtual T doSomething(T const& in) = 0;
    Base(T const& data) : data_(data) {}
    T data_;
 };

 struct Concrete : public Base<int>
 {
    Concrete(int d) : Base(d) {}

    virtual int doSomething(int const& in)
    {
       return data_*in;
    }
 };

 int main()
 {
    Concrete a(20);
    int b = a.doSomething(10);
 }

另一方面,似乎允许不使用模板类型的类模板中的虚函数,对吗?

A 类模板的虚函数可以使用任何东西 - 不限于不使用模板tye。

我的例子应该说清楚。

如果虚拟函数不使用模板类型作为参数或返回类型但是处理模板类型的数据呢?这是有效的C ++吗?

A 是的,它会。

同样,我的例子应该清楚说明。

编辑:扩展示例

 template <typename T>
 struct Base
 {
    virtual T fun1(T const& in) = 0;

    virtual T fun2(int in) = 0;

    virtual int fun3(T const& in) = 0;

    virtual int fun4(int in) = 0;

    Base(T const& data) : data_(data) {}
    T data_;
 };

 struct Concrete : public Base<int>
 {
    Concrete(int d) : Base(d) {}

    virtual int fun1(int const& in)
    {
       return data_*in;
    }

    virtual int fun2(int in)
    {
       return fun1(in);
    }

    virtual int fun3(int const& in)
    {
       return fun1(in);
    }

    virtual int fun4(int in)
    {
       return fun1(in);
    }
 };

 int main()
 {
    Concrete a(20);
    int b = a.fun1(10);
    int c = a.fun2(10);
    int d = a.fun3(10);
    int e = a.fun4(10);
 }

答案 1 :(得分:0)

这完全有效。但是,在这里,您可以使用专门化或仅重载相同的行为,例如

template<typename T>
struct Base
{
    bool compare() const { return val(value1) + val(value2) < val(value3); }

protected:
    T value1, value2, value3;

private:
    template<typename U>
    static U val(U a) { return a; }
    static int val(const ComplexClass& a) { return a.getInt(); }
};

最好在真正需要的时候保留虚拟功能。

尽量在一个地方收集尽可能多的共享代码,尽量减少专门的内容。