一直对接口没有什么概念,感觉接口就是C++中的多态。个人理解,接口的作用就是让外部调用者不用关心这个类的类型,让公用的逻辑可以重用。
一个例子:
我们说燕子会飞,会喝水。按照一般的写法,我们需要定义一个燕子的类,然后写了会飞的函数。假设有这么个流程,燕子飞到河边,喝水。这个过程中要用燕子类的指针调用。这个过程没问题,能很快搞定。
没过多久,PM需要加功能(你懂的),我们要写个鸽子飞到河边,喝水。鸽子的飞法和喝水方法与燕子自然不同。鸽子类必然要重写。但是飞到河边,喝水。这个流程能不能复用呢。因为如果我们这个流程说的是,鸟飞到河边,喝水。是不是就能够通用于燕子,鸽子,甚至是以后还可能有的喜鹊什么的。。
C++中的类继承:
在C++中,我们通常会先定义一个鸟类(基类),基类中定义了飞行,喝水等虚函数。然后,我们通过继承基类,声明了鸽子,燕子等派生类。鸽子和燕子的飞行和喝水的方法会重写掉基类中的方法(函数)。
然后,我们写这个流程时,直接使用基类来表示鸽子和燕子。在运行时,传入的类如果是燕子,就会使用燕子的飞行和喝水方法,传入的类如果是鸽子,就是鸽子的飞行和喝水方法。
以后不同的鸟类,比如喜鹊,它只需要继承自鸟类,也可以直接套到这个飞行再喝水的流程中。
这就是C++的解决方法,它让类和我们现实生活中的分类方法相对应。动物-鸟类-喜鹊,C++也可以按照这种关系组成相应的类。C++中并没有专门说明这是接口。
Go语言中的接口:
Go语言中,有专门的关键词interface来定义接口。接口中,定义了要用的函数。比如:
这就好像一个类型,它的实例是一个指针,传给这个指针的类必须包含接口中定义的方法。比如:
05 |
func (t *PType) post() { |
08 |
func (t *PType) change() { |
为什么说接口类是一个指针类型呢,因为传递给接口实例的是地址。所以可以把它看作C++中的基类指针来使用。
只要把上面第三行的 it=pty改成it=&pty即可编译通过。&是取址。
如果我定义了别的类,只需要类中有Inter接口的那几个函数,我也可以直接使用接口的实例来调用类的方法。就好像,我先定义了各种鸟类,然后我发现它们可以抽象出统一的接口,于是我把它们的共同点抽象出来,成为一个接口。
C++和Go在接口上的区别:
Go语言和C++最大的不同在于,它不需要使用基类。因为基类肯定定义在派生类之前,派生类还需要继承基类。如果基类设计的不好,那么整个代码调整起来就会很难,因为关联很多。它是一种总-分的结构,基类为总,然后分成各种派生类。
Go则是反过来,是一种分-总的机构,原本是分,再是总。各种类可以随便写。接口可以在写完类后再定义。当然,有些东西该统一的还是需要统一的。不过,接口可以最后写,而不是C++那样,必须先有基类。这增加了不少灵活性。
感觉上,C++通过派生,把共同点派生出去。而Go则是从原本的类中,提炼出共同点。
当然,C++并不是没有Go的这种特性。因为重用的这部分是偏向逻辑的。C++中认为,逻辑的重用应该和类型无关,所以它直接把逻辑也给抽象掉了。提供了一个template,即模板。模板可以直接支持各种类型。其实和Go的interface最对应的应该是模板。类的继承和操作符重载是为了让模板更方便使用(因为只有有了共同点,我们才能抽象出来)。因此C++中就没有接口这种说法。
以上是我对接口的理解。不知道对不对,如有错误望不吝赐教。
转载请注明:旅途@KryptosX » 对C++和Go语言中接口的理解