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())
|
输出为:
比如只要一个对象实现了能够返回一个迭代器的__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)
|
输出为:
在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!
|
外部函数的参数是一个基类类型的指针,此时在基类中声明一个函数为虚函数,在子类中重写这个虚函数,此时可以把子类对象直接传给这个函数,它会动态调用子类所实现的虚函数。注意这个和子类重定义父类函数进行覆盖并不一样。此外只有类的成员函数可以被声明为虚函数,注意区分虚函数和纯虚函数,这两个完全是出于不同的目的。