C ++模板多态性 [英] C++ Templates polymorphism

查看:112
本文介绍了C ++模板多态性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这种结构的类。

 类接口{
...
}

class Foo:public Interface {
...
}

template< class T>
class Container {
...
}

有一个其他类Bar的构造函数。

  Bar(const Container< Interface>& bar){
。 ..
}



当我以这种方式调用构造函数时,错误。

 容器< Foo>容器 (); 

Bar * temp = new Bar(container);

有什么问题?不是模板多态?

解决方案

我认为你需要的确切术语是模板协方差,意味着如果B继承从A,然后以某种方式 T T 继承。这不是在C ++中的情况,也不是与Java和C#泛型*。



有一个很好的理由避免模板协方差:这将只是删除所有类型安全在模板类中。让我用下面的例子解释:

  //假设下面的类层次结构
class Fruit {...} ;

class Apple:public Fruit {...};

class Orange:public Fruit {...};

//现在我将使用这些类型来实例化类模板,即std :: vector
int main()
{
std :: vector< Apple> ; apple_vec;
apple_vec.push_back(Apple()); //这里没有问题

//如果模板是协变的,以下是合法的
std :: vector< Fruit> & fruit_vec = apple_vec;

// push_back需要一个Fruit,所以我可以传递一个Orange
fruit_vec.push_back(Orange());

//哦不!我只是在我的苹果篮里添加了一个橙色!
}



因此,您应该考虑 T& / code>和 T 作为完全不相关的类型,而不管A和B之间的关系。



那么你如何解决你面对的问题呢?在Java和C#中,您可以分别使用有界通配符约束

  // Java code 
Bar(Container< ;? extends Interface){...}

// C#code
Bar< T&其中T:Interface {...}

下一个C ++标准以前的C ++ 0x))最初包含一个更强大的机制,名为概念,这将允许开发人员强制对模板参数的语法和/或语义要求,但不幸地推迟到以后的日期。但是,Boost有一个概念检查库,您可能会对此感兴趣。



然而,概念可能对你遇到的问题有点过分,使用一个简单的静态assert由 @ gf 可能是最好的解决方案。



*更新: 4,可以标记协变或逆变的通用参数。 / p>

I have this structure of classes.

class Interface{
...
}

class Foo : public Interface{
...
}

template <class T>
class Container{
...
}

And I have this constructor of some other class Bar.

Bar(const Container<Interface> & bar){
...
}

When I call the constructor this way I get "no matching function" error.

Container<Foo> container ();

Bar * temp = new Bar(container);

What is wrong? Are not templates polymorphic?

解决方案

I think the exact terminology for what you need is "template covariance", meaning that if B inherits from A, then somehow T<B> inherits from T<A>. This is not the case in C++, nor it is with Java and C# generics*.

There is a good reason to avoid template covariance: this will simply remove all type safety in the template class. Let me explain with the following example:

//Assume the following class hierarchy
class Fruit {...};

class Apple : public Fruit {...};

class Orange : public Fruit {...};

//Now I will use these types to instantiate a class template, namely std::vector
int main()
{
    std::vector<Apple> apple_vec;
    apple_vec.push_back(Apple()); //no problem here

    //If templates were covariant, the following would be legal
    std::vector<Fruit> & fruit_vec = apple_vec;

    //push_back would expect a Fruit, so I could pass it an Orange
    fruit_vec.push_back(Orange()); 

    //Oh no! I just added an orange in my apple basket!
}

Consequently, you should consider T<A> and T<B> as completely unrelated types, regardless of the relation between A and B.

So how could you solve the issue you're facing? In Java and C#, you could use respectively bounded wildcards and constraints:

//Java code
Bar(Container<? extends Interface) {...}

//C# code
Bar<T>(Container<T> container) where T : Interface {...}

The next C++ Standard (known as C++1x (formerly C++0x)) initially contained an even more powerful mechanism named Concepts, that would have let developers enforce syntaxic and/or semantic requirements on template parameters, but was unfortunately postponed to a later date. However, Boost has a Concept Check library that may interest you.

Nevertheless, concepts might be a little overkill for the problem you encounter, an using a simple static assert as proposed by @gf is probably the best solution.

* Update: Since .Net Framework 4, it is possible to mark generic parameters has being covariant or contravariant.

这篇关于C ++模板多态性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆