什么是编译时多态性,为什么它只适用于函数?
5 回答
回到过去,“编译时多态性”意味着函数重载。它仅适用于函数,因为它们都是你可以重载的。
在当前的 C++ 中,模板改变了这一点。Neil Butterworth 已经举了一个例子。另一个使用模板专业化。例如:
#include <iostream>
#include <string>
template <class T>
struct my_template {
T foo;
my_template() : foo(T()) {}
};
template <>
struct my_template<int> {
enum { foo = 42 };
};
int main() {
my_template<int> x;
my_template<long> y;
my_template<std::string> z;
std::cout << x.foo << "\n";
std::cout << y.foo << "\n";
std::cout << "\"" << z.foo << "\"";
return 0;
}
这应该 yield 42
, 0
, and ""
(一个空字符串)——我们得到了一个对每种类型都有不同作用的结构。
这里我们有类的“编译时多态性”而不是函数。我想如果你想争论这一点,你可以声称这至少部分是构造函数(一个函数)在至少一种情况下的结果,但专门版本的my_template
甚至没有构造函数。
编辑:至于为什么这是多态性。我将“编译时多态性”放在引号中是有原因的——它与普通的多态性有些不同。尽管如此,我们得到的效果类似于我们期望从重载函数中得到的效果:
int value(int x) { return 0; }
long value(long x) { return 42; }
std::cout << value(1);
std::cout << value(1L);
函数重载和特化产生了类似的效果。我同意“多态性”是否适用于任何一个问题都存在一些问题,但我认为它同样适用于一个和另一个。
对于编译时多态性,通常意味着您可以拥有多个具有相同名称的函数,并且编译器将在编译时根据参数选择使用哪一个:
void foo(int x);
void foo(float y);
//Somewhere else
int x = 3;
foo(x); //Will call first function
float y = 2;
foo(y); //Will call second function
该函数foo
被称为重载。各种类型的模板实例化也可以称为编译时多态性。
编译时多态性是指 C++ 模板编程的术语。例如,在编译时,您可以通过 std::vector 包含的内容确定其实际类型:
std::vector <int> vi;
std::vector <std::string> vs;
我不确定您为什么认为它仅限于功能。
仅适用于函数的是模板参数推导。如果我有一个函数模板:
template <typename T>
void foo(T &t);
然后我可以做int a = 0; foo(a);
,这将相当于int a = 0; foo<int>(a);
。编译器解决了我的意思foo<int>
。至少,它应该使用它foo<int>
- 如果这不是我的意思,那么对我来说运气不好,我本可以写foo<unsigned int>(a);
或其他什么。
但是,如果我有一个类模板:
template <typename T>
struct Foo {
T &t;
Foo(T &t) : t(t) {}
T &getT() { return t; }
};
那我就不行了int a = 0; Foo(a).getT();
。我必须指定Foo<int>(a)
. 不允许编译器解决我的意思Foo<int>
。
所以你可能会说类模板比函数模板“更少多态”。多态性通常意味着您不必编写代码来明确对象的类型。函数模板允许这样做(在这种特殊情况下),而类模板则不允许。
至于为什么会这样-标准是这样说的,我不知道为什么。通常的怀疑是(a)它太难以实现,(b)它没有用,在标准委员会看来,或者(c)它在语言的其他地方产生了一些矛盾或歧义。
但是你仍然可以用类做其他类型的多态性:
template <typename T>
struct Foo {
T &t;
Foo(T &t): t(t) {}
void handleMany(int *ra, size_t s) {
for (size_t i = 0; i < s; ++i) {
t.handleOne(ra[i]);
}
}
};
这通常也称为编译时多态性,因为就模板的作者而言,t.handleOne
它可以是任何东西,并且它会在必要时解析,“稍后”在编译时实例化 Foo。
编译时多态适用于函数和运算符重载。