C++中不是基本上只有一种多态性"kind"吗?
Isn't there essentially only one "kind" of polymorphism in C++?
也就是:函数重载。
我的意思是
base_ptr->derived_class_method()
本质上是
derived_class_method(base* this_ptr)
这是通过函数重载实现的多态性。
通过模板的多态性也是如此,包括CRTP等。
因此,考虑到最广泛的实现,所有"各种"多态性似乎都归结为函数重载。
还是我错过了什么?
本质上不是只有一种吗
这取决于你如何定义"种类"。维基百科将多态性分为三类:即席、参数和子类型。所有这些多态性都存在于C++中。
也就是:函数重载
在C++语言的上下文中,函数重载具有特定的含义。也就是说,模板和虚拟函数都不能被称为函数重载。
然而,抽象地说是的,所有的多态性(在C++中,也许在一般的计算机科学中)都归结为选择一个函数实现而不是另一个。
您缺少了一些东西,但主要有一个关键区别:重载是编译时,而重写(即virtual
)可以是运行时。有了过载,你可以这样做:
void make_a_sound(Cat const& cat)
{
std::cout << cat << ": meow" << std::endl;
}
void make_a_sound(Dog const& dog)
{
std::cout << dog << ": wurf" << std::endl;
}
int main()
{
Cat c;
Dog d;
make_a_sound(c);
make_a_sound(d);
}
但你不能这样做:
class Animal
{
virtual void make_a_sound() = 0;
};
void make_a_sound(std::vector<Animal*> const& animals)
{
for (Animal* a : animals)
a->make_a_sound();
}
在第一个示例中,编译器将选择在编译时调用的正确函数。你可以用不同的名称命名这两个函数(即make_a_sound_cat
和make_a_sound_dog
)——如果它的工作原理相同,那么能够重用相同的名称只是一种方便。
然而,在第二个例子中,编译器生成代码,以便在运行时,您的程序将找出每种动物的确切性质并调用正确的方法。
基本上有三种类型的多态性:
1.临时
2.参数
3.子类型
1.特别:
特设多态性允许具有相同名称的函数对每种类型采取不同的操作。(这是你举的例子)
示例:
int add(int a, int b) {
return a + b;
}
std::string add(const char *a, const char *b) {
std::string result(a);
result += b;
return result;
}
2.参数:
参数多态性为任何类型提供了执行相同代码的方法。它是通过C++中的模板来实现的。(所以给定定义,你可以说这也是一种自动功能过载)
3.分型:
子类型是通过基类指针和引用使用派生类来实现的。因此,在实践中,我们使用子类和虚拟方法进行子类型划分。(这不是功能过载)
class Mammal
{
public:
Mammal() {};
virtual ~Mammal() {};
virtual std::string SendLoudNoise()
{
std::string str("I am a generic mammal");
return str;
}
};
class Dog : public Mammal {
public:
Dog() {};
virtual ~Dog() {};
std::string SendLoudNoise()
{
std::string str("Woof woof!");
return str;
}
};
class Cat : public Mammal {
public:
Cat() {};
virtual ~Cat() {};
std::string SendLoudNoise()
{
std::string str("--- Twitch my tail ---");
return str;
}
};
int main()
{
Mammal* pAnimal[2] = { new Dog, new Cat};
for (int i = 0 ; i < 2; ++i)
{
std::cout << pAnimal[i]->SendLoudNoise() << std::endl;
delete pAnimal[i];
}
return 0;
}
函数重载无法实现子类型。因为它是"运行时多态性"。
C++中有三个。
主要区别在于"多晶型"的独立性。
- 过载是一种特殊的多态性
它是特别的,因为您只使用相同的名称来表示几个不同的函数,这些函数不需要以任何方式关联。
示例:
int foo(int);
void foo(const std::string&, double);
- 函数模板提供了参数多态性
这些仅取决于其参数的接口(广义的"接口",而不是Java的意义)。
示例:
template<typename T>
T id(T t)
{
return t;
}
如果T
是可复制构造的,则为每个T
定义一个函数。
一个有效的问题是"这不是一种自动重载吗?",答案是C++中的差异并不大
在其他语言中,id
可能只是一个函数,可用于任何类型。
- "虚拟功能"(override)是子类型
这些都与特定的类型层次结构紧密相连。
您会注意到重载要求多晶型具有不同的原型,而其他两个则要求原型相同。
此外,虚拟函数(通常)在运行时绑定,而其他两个函数总是在编译时绑定(在C++中)。
这里是C++中所有可能多态性的完整列表:
- 特设多态性
- 强制多态性
- 重载多态性,可以
- 函数重载
- 操作员过载
- 普遍多态性
- 内含物多态性(亚型)
- 参数或通用多态性
- 多态性和功能结合
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- C++boost序列化多态性问题
- 如何查找哪个类对象位于数组的特定索引上(多态性)
- 如何在多线程中正确使用unique_ptr进行多态性?
- 具有智能指针的多态性
- 在 C++ 中在堆栈上创建实例时如何保持多态性?
- 继承/多态性 - 我是否被迫使用"protected"变量?
- C++ 多态性在代码::块 17.12 中不起作用
- C++ 泛型和多态性:这种模式可行吗?
- 为什么我们实际上需要运行时多态性?
- 如何在这个简单的最小示例中实现多态性?
- 如何使用静态多态性在 int 和指针类型之间进行转换?
- 无法初始化已知大小的矢量指针,该大小不会因多态性而更改
- 在继承层次结构中将方法定义为虚拟方法一次,以使多态性发挥作用
- C++中不是基本上只有一种多态性"kind"吗?
- 有没有可能创建一个数组,在初始化时我们不知道元素的数量?(处理遗传/多态性)
- 在c++中使用多态性和继承来处理一篮子水果的正确方法是什么?
- 在这种情况下,哪种设计模式有利于实现运行 tiime 多态性