Python的鸭子类型和cpp的虚函数

Python的鸭子类型和cpp的虚函数

目标

定义一个函数,不管传递给这个函数的究竟是什么对象,函数能通过同一个接口调用到适应各自对象的实现方法。也就是实现接口的复用,实现动态多态。

python的鸭子类型

python是一个动态语言,这种多态是自然的..在python中对象的类型并不重要,只要这个对象实现了某个函数所需的特定的协议,这个对象就能够被这个函数所调用:

1
2
3
4
5
6
7
8
9
10
11
12
class Dog:
def bark(self):
print('wang!')
class Cat:
def bark(self):
print('miao!')

def say(animal):
animal.bark()

say(Dog())
say(Cat())

输出为:

1
2
wang!
miao!

比如只要一个对象实现了能够返回一个迭代器的__iter__方法,他就是可迭代对象,就可以去以某种方式迭代他,比如:

1
2
3
4
5
6
class SomeIter():
def __iter__(self):
return (i for i in range(10))

for i in SomeIter():
print(i)

输出为:

1
2
3
4
5
6
7
8
9
10
0
1
2
3
4
5
6
7
8
9

在python中这种所谓的鸭子类型很自然,有时候甚至会忘记这是一种多态。

cpp的虚函数

在静态语言中想要实现接口复用并不像动态语言这样自然,因为定义一个函数必须指定参数的类型。在cpp中提供了虚函数的方式来实现这种多态性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
using namespace std;

class Animal{
public:
virtual void bark(){
cout << "i don't know how to bark!" << endl;
}
};

class Dog: public Animal{
public:
void bark(){
cout << "wang!" << endl;
}
};

class Cat: public Animal{
public:
void bark(){
cout << "miao!" << endl;
}
};

void sing(Animal* animal){
animal -> bark();
}

int main(){
sing(new Animal());
sing(new Dog());
sing(new Cat());
return 0;
}

输出为:

1
2
3
i don't know how to bark!
wang!
miao!

外部函数的参数是一个基类类型的指针,此时在基类中声明一个函数为虚函数,在子类中重写这个虚函数,此时可以把子类对象直接传给这个函数,它会动态调用子类所实现的虚函数。注意这个和子类重定义父类函数进行覆盖并不一样。此外只有类的成员函数可以被声明为虚函数,注意区分虚函数和纯虚函数,这两个完全是出于不同的目的。