模板和多态有什么区别
大家好,我对模板和多态性有疑问.根据定义,多态性提供代码可重用性,并且模板在某种意义上允许用户通过提供具有不同数据类型的通用编程来使用相同的代码.那么在模板上使用多态性有什么好处.这可能是一个愚蠢的问题,但我很想知道确切的区别.
Hi all I have a doubt regarding templates and polymorphism. By definition polymorphism provides code reusability, and templates in some sense allows the user to use the same code by providing generic programming with different data types. So what is the benefit of using polymorphism over templates. It might be a silly questions but I am curious to know the exact difference.
推荐答案
你好像误解了什么是多态性.
You seem to misunderstand what polymorphism is.
多态性的核心与派生类无关.多态性仅仅意味着在不知道所有类型的情况下使用类型的能力.多态性不是使用具体类型,而是依赖于某种形式的原型来定义它所采用的类型.任何适合该原型的类型都被接受.
Polymorphism, at its core, has nothing to do with derived classes. Polymorphism simply means the ability to use a type without knowing everything about it. Rather than using a concrete type, polymorphism relies on some form of prototype to define what types it takes. Any types that fit that prototype are accepted.
在 C++ 中,运行时多态性是通过从包含虚函数的基类派生类来提供的.基类和虚函数构成多态原型.为接受调用这些虚函数的基类而编写的代码将接受从基类派生的任何类实例.
Runtime polymorphism, in C++, is provided by deriving classes from a base class that contains virtual functions. The base class and virtual functions form the polymorphic prototype. Code written to accept the base class that calls these virtual functions will accept any class instance derived from the base class.
编译时多态是发生在编译时...的多态;)这意味着编译器必须知道发生了什么.您可能已经针对多态原型编写了 C++ 代码,但编译器并不关心.您会在编译后获得特定的具体类型.
Compile-time polymorphism is polymorphism that happens... at compile time ;) What this means is that the compiler must know what is going on. You may have written the C++ code against a polymorphic prototype, but the compiler doesn't care. You get specific concrete types post-compilation.
编译时多态性由 C++ 中的模板提供.模板函数或类可以采用符合原型的任何类型,通常称为概念".与基类和虚函数不同,原型是隐式:原型仅由模板函数/类使用类型的方式来定义.
Compile-time polymorphism is provided by templates in C++. A template function or class can take any type which conforms to a prototype, usually called a "concept". Unlike base classes and virtual functions, the prototype is implicit: the prototype is defined only by how the type is used by the template function/class.
如果你有这个模板功能:
If you have this template function:
template<typename T>
void Stuff(T &t)
{
t.call(15);
}
T
上有一个隐式 要求.这个要求是它有一个名为call
的成员函数.此成员函数必须有一个可以用整数值调用的重载.
There is an implicit requirement on T
. This requirement is that it has a member function called call
. There must be a single overload of this member function which can be called with an integer value.
这意味着可以使用恰好适合此原型的任何类型.
This means that any type that happens to fit this prototype can be used.
模板多态比继承多态更广泛,因为它可以被更广泛的类型数组使用.必须专门设计一个类型以使用继承多态性;你必须从一个类派生.类型可以非破坏性地(即:您不必更改类型本身)适应模板多态性.如果您的模板原型设计良好,则更是如此:
Template polymorphism is more broad than inheritance polymorphism, because it can be used by a broader array of types. A type has to be designed specifically to use inheritance polymorphism; you have to derive from a class. A type can be non-destructively (ie: you don't have to change the type itself) adapted to template polymorphism. Even moreso if your template prototype is well designed:
template<typename T>
void Stuff(T &t)
{
call(t, 15);
}
这个版本的Stuff
所需要的只是有一些函数接受一个T&
和一个整数值.如果我有一些想要与 Stuff
一起使用的类型,我所要做的就是在适当的命名空间(即该类型所在的命名空间)中定义一个 call
函数中定义).这将工作得很好.所有这些都没有修改类型本身.
All that this version of Stuff
requires is that there is some function that takes a T&
and an integer value. If I have some type that I want to use with Stuff
, all I have to do is define a call
function in an appropriate namespace (namely, the namespace that the type was defined in). And this will work just fine. All without modifying the type itself.
当然,编译时多态性是……编译时.如果我想要一些用户输入或数据文件来选择多态类型,模板不会有很大帮助(尽管类型擦除,一种基于模板的技术,可以提供帮助).运行时多态的主要好处是它确实是运行时.
Of course, compile-time polymorphism is... compile-time. If I want some user input or data file to select the polymorphic type, templates aren't going to help a whole lot (though type erasure, a template-based technique, can help). The principle benefit of runtime polymorphism is that it is indeed runtime.
另一个好处是它的原型更精确.一切都明确说明了继承.基类中的虚函数接口布局清晰.编译器将阻止您尝试错误地使用该基类(调用其上不存在的方法).事实上,一个像样的 IDE 会指导您的代码,这样您就只能看到基类上的方法.
Another benefit is that it is more precise about its prototypes. Everything is explicitly stated about inheritance. The virtual function interface in a base class is clearly laid out. The compiler will stop you from attempting to use that base class incorrectly (calling methods that don't exist on it). Indeed, a decent IDE will guide your code so that you will only see the methods on the base class.
模板多态性更加隐含.由于 C++ 无法说明特定模板函数/类放在类型上的原型,因此很容易意外地在模板类型上调用一些你不应该调用的东西.只有当您尝试使用不适合原型的类型时,编译器才会检测到这一点.即使这样,您通常也会收到大量错误(取决于您的模板代码嵌套的深度),这使得您很难知道问题出在哪里.
Template polymorphism is a lot more implicit. Since C++ has no way of spelling out the prototype that a particular template function/class puts on a type, it's very easy to accidentally call something on a template type that you shouldn't. The compiler will only detect this when you try to use a type that doesn't fit the prototype. And even then you will generally get a massive error spew (depending on how deeply nested your template code is) that makes it difficult to know where the problem is.
实现隐式模板多态原型也困难得多,因为它没有被详细说明.实现派生类需要遍历基类,查看所有虚函数并实现它们.为模板原型执行此操作要困难得多,除非某处有说明它的文档.如果你未能实现某些东西,你会再次得到一个错误,通常不会出现问题.
It's also a lot harder to implement the implicit template polymorphic prototype, since it isn't spelled out. Implementing a derived class requires walking through the base class, looking at all of the virtual functions, and implementing them. Doing this for a template prototype is much more difficult, unless there is documentation somewhere that spells it out. If you fail to implement something, you again get an error spew that is generally less than forthcoming about the problem.
相关文章