代码之家  ›  专栏  ›  技术社区  ›  Till Theis

模板多态性不起作用?

  •  2
  • Till Theis  · 技术社区  · 15 年前

    我正在构建一个小的模板层次结构,并尝试利用类多态性。下面是一些示例代码(不编译)来演示它:

    template<typename T>
    struct A
    {};
    
    template<typename T>
    struct B
    {
        B (A<B> *) {}
    };
    
    struct C : public B<int>
    {
        C(A<C> *p) : B<int>(p) {} // error
    };
    
    
    int main() {
        A<C> ac;
        C c(&ac);
    }
    

    我的编译器(os x上的gcc 4.01)在指定行上引发以下错误:

    error: no matching function for call to ‘B<int>::B(A<C>*&)’
    

    但是根据我的逻辑假设,代码应该可以工作,因为

    C       == B<int>
    B<int>  == B<T>
    
    => A<C> == A<B<T> >
    

    有人能指出我的错误在哪里,以及如何解决吗?


    编辑

    答案似乎是,我的问题不能通过常规的继承树来解决,因为模板是静态的来识别多态性。那么铸造是合法的吗 A & LT;C> A<B<int> 从设计的角度来看,强制多态性是可怕的?

    struct C : public B<int>
    {
        C(A<C> *p) : B<int>((A<B<int> > *)p) {}
    };
    

    这个问题有什么“好”的解决办法吗?

    2 回复  |  直到 15 年前
        1
  •  3
  •   Cătălin Pitiș    15 年前

    A<B<int>与A<C>的类型不同,即使C是从B<int>派生的。

    因此,类型A<C>*的构造函数C的参数与构造函数B<int>请求的参数A<B<int>不兼容。

    后期编辑: 使用模板化构造函数:

    template<typename T>
    struct B
    {
        template< typename E>
        B (E *) {}
    };
    
    struct C : public B<int>
    {
        template< typename E>
        C(E *p) : B<int>(p) {}
    };
    

    然而,这个问题太抽象,无法给出解决方案…

        2
  •  4
  •   Pavel Minaev    15 年前

    首先,这是:

    C       == B<int>
    B<int>  == B<T>
    

    是错误的。正确的形式是:

    C 来源于 B<int>

    B<INT> 是的实例 B<T>

    这完全是另一回事。现在,转到问题的关键。

    C++模板不是变体。特别是,给定两个类 Base Derived 和类模板 Foo<T> , Foo<Derived> 不是的子类 Foo<Base> 以及指向前者的指针和引用不能转换为后者。其基本原理是,这样做并不总是安全的。例如,假设它是可能的,并且 std::list<Derived>& 浇注到 std::list<Base>& . 如果是这样,我可以写:

    struct Base {...};
    struct Derived1 : Base {...};
    struct Derived2 : Base {...};
    
    std::list<Derived1> dl;
    std::list<Base>& bl = dl;
    bl.push_back(Derived2()); // dl is a list of Derived1, but we just put
                              // an instance of Derived2 into it...
    

    所以这是非法的(而且允许它也存在实现问题)。此外,也没有办法选择方差的C++模板。每个模板实例化都只是一个不同的类,它的基类只是定义中基类列表中特定列出的那些。它与同一类模板的其他实例化没有特殊关系。

    因此,在你的情况下, A<B<int>> 不是同一类型 A<C> ,它们之间也没有任何隐式(或有意义的显式)指针转换。