专门化模板类时的继承

Inheritance when specializing a template class

本文关键字:继承 专门化      更新时间:2023-10-16

我希望能够做这样的事情:

template<typename T>
class myClass{
    public:
        double Foo(double x){return x;}
}
template<>
class myClass<SpecialType>{
    public:
        double Bar(double x){return x+1.0;}
}

现在,我想实例化专门化,但仍然可以访问方法Foo,而无需重写专门化中的整个内容,即:

myClass<SpecialType> A;
double y = A.Foo(1.0);

是否有办法做到这一点与我目前的设置,或者我需要写一个"主"类,以继承Foo() ?

两个选项:

  • 构造一个公共基类,在其中放置所有类型无关的东西(推荐):

    struct myClassBase
    {
        virtual double Foo(double x) const {return x+1.0;}
    };
    template<typename T> struct myClass : public myClassBase
    {
         //...
    };
    template<>
    struct myClass<SpecialType> : public myClassBase
    {
        double Bar(double x){return x+1.0;}
    }
    

    当你的函数不依赖于模板形参时,建议这样做。

  • 从你的非特化类派生:

    template<>
    struct myClass<SpecialType> : public myClass</* be careful what to write here */>
    {
        double Bar(double x){return x+1.0;}
    }
    
    但是,您必须小心传递给非特化类模板的类型(特别是当您的成员函数依赖于模板类型时——为了使它们有意义,它们应该以某种方式依赖于模板类型)。
  • 另一个更静态的选择是应用策略模式:将所有功能转移到一些小的策略类,然后通过这些组合构建所需的类(缺点:您必须再次公开功能),或者通过多重继承(在这里您不必重述整个事情,但要再次小心避免歧义)。


EDIT:根据您的评论,下面是完成相同任务的CRTP方法:

template<typename Derived>
struct myClassBase
{
    double Foo(double x) const
    {
        return static_cast<Derived const&>(*this).specialMember(x);
    }
    //all other stuff independent of the derived class specialization
    //possibly define specialMember once:
    virtual double specialMember(double x) const { return x; }
}
template<typename T> struct myClass : public myClassBase<myClass<T> >
{
    //... special member of Base class is sufficient
};
template<> struct myClass<SpecialType> : public myClassBase<myClass<SpecialType> >
{
    virtual double specialMember(double x) const { return x+1.0; }
};

再次注意,这只在模板类型真正涉及函数求值时才有意义。

另一方面,如果double Foo(double x)上的重载是足够的,忘记整个模板的东西,并使用第一个替代。

您可以重复专门化中的公共部分

template<typename T>
class myClass
{
public:
    double Foo(double x){return x;}
};
template<>
class myClass<SpecialType>
{
public:
    double Foo(double x){return x;}
    double Bar(double x){return x + 1.0;}
};

或使用其他辅助类:

template<typename T> struct BarHelper<T> {};
template<> struct BarHelper<SpecialType>
{
    double Bar(double x) {return x + 1.0;}
};
template<typename T>
class myClass : public BarHelper<T>
{
public:
    double Foo(double x){return x;}
    // inherit Bar method for SpecialType.
};