【问题标题】:Virtual function in class template, that doesn't have the template type as parameter/return value类模板中的虚函数,没有模板类型作为参数/返回值
【发布时间】:2014-04-08 20:45:08
【问题描述】:

据我所知,由于 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:我知道模板专业化可以完成类似的事情,但我想知道这种方式是否也可以。

【问题讨论】:

  • 它完全有效,并且与任何其他(非模板)类具有虚函数一样工作。
  • 模板方法 != 模板类
  • 我想Paranaix 想说的是:问题出在虚函数模板,而不是类模板的虚成员函数。只要有固定数量的成员函数,vtable的大小是已知的,没有问题。但是成员函数模板可以在不同的地方为任意数量的模板参数(以及每个翻译单元中的不同参数)实例化。

标签: c++ class templates virtual


【解决方案1】:

Q据我所知,由于 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);
 }

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

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

我的例子应该说明这一点。

Q 不使用模板类型作为参数或返回类型但对模板类型的数据起作用的虚函数呢?那是有效的 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);
 }

【讨论】:

  • 感谢您的回复。我很确定我在某处使用模板类型的具有虚函数的类模板表现得像虚成员函数模板(这是不允许的)。但很明显我做错了什么。还有一件事:您的示例代码将无法编译,因为虚拟函数是纯虚拟的。出于某种原因,我的编译器至少需要空括号而不是“= 0”。这是我的编译器有问题还是我做错了什么?
  • @user1271373 使用 g++ 4.7.3 编译和链接简单示例和扩展示例没有问题。
【解决方案2】:

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

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

最好在真正需要的时候保留虚函数。

并尝试在一个地方收集尽可能多的共享代码,尽量减少需要专门化的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-10
    • 2022-01-09
    • 2018-04-06
    • 1970-01-01
    相关资源
    最近更新 更多