天天看点

对C++和Go语言中接口的理解

一直对接口没有什么概念,感觉接口就是c++中的多态。个人理解,接口的作用就是让外部调用者不用关心这个类的类型,让公用的逻辑可以重用。

我们说燕子会飞,会喝水。按照一般的写法,我们需要定义一个燕子的类,然后写了会飞的函数。假设有这么个流程,燕子飞到河边,喝水。这个过程中要用燕子类的指针调用。这个过程没问题,能很快搞定。

没过多久,pm需要加功能(你懂的),我们要写个鸽子飞到河边,喝水。鸽子的飞法和喝水方法与燕子自然不同。鸽子类必然要重写。但是飞到河边,喝水。这个流程能不能复用呢。因为如果我们这个流程说的是,鸟飞到河边,喝水。是不是就能够通用于燕子,鸽子,甚至是以后还可能有的喜鹊什么的。。

在c++中,我们通常会先定义一个鸟类(基类),基类中定义了飞行,喝水等虚函数。然后,我们通过继承基类,声明了鸽子,燕子等派生类。鸽子和燕子的飞行和喝水的方法会重写掉基类中的方法(函数)。

然后,我们写这个流程时,直接使用基类来表示鸽子和燕子。在运行时,传入的类如果是燕子,就会使用燕子的飞行和喝水方法,传入的类如果是鸽子,就是鸽子的飞行和喝水方法。

以后不同的鸟类,比如喜鹊,它只需要继承自鸟类,也可以直接套到这个飞行再喝水的流程中。

这就是c++的解决方法,它让类和我们现实生活中的分类方法相对应。动物-鸟类-喜鹊,c++也可以按照这种关系组成相应的类。c++中并没有专门说明这是接口。

go语言中,有专门的关键词interface来定义接口。接口中,定义了要用的函数。比如:

<code>1</code>

<code>type inter interface {</code>

<code>2</code>

<code>     </code><code>post()</code>

<code>3</code>

<code>     </code><code>change()</code>

<code>4</code>

<code>}</code>

这就好像一个类型,它的实例是一个指针,传给这个指针的类必须包含接口中定义的方法。比如:

<code>01</code>

<code>type ptype </code><code>struct</code> <code>{</code>

<code>02</code>

<code>     </code><code>x </code><code>int</code>

<code>03</code>

<code>04</code>

<code>// 接收者是指针</code>

<code>05</code>

<code>func (t *ptype) post() {</code>

<code>06</code>

<code>    </code><code>fmt.println(t.x)</code>

<code>07</code>

<code>08</code>

<code>func (t *ptype) change() {</code>

<code>09</code>

<code>    </code><code>t.x=5</code>

<code>10</code>

为什么说接口类是一个指针类型呢,因为传递给接口实例的是地址。所以可以把它看作c++中的基类指针来使用。

<code>//接上面的代码</code>

<code>pty := ptype{4}</code>

<code>it = pty  </code><code>//编译失败</code>

<code>//报错:cannot use pty (type ptype) as type inter in assignment:</code>

<code>5</code>

<code>//      ptype does not implement inter (change method has pointer receiver)</code>

<code>6</code>

<code>//这个意思指的是无法把ptype转换为inter类型,因为inter需要的是pointer。</code>

只要把上面第三行的 it=pty改成it=&amp;pty即可编译通过。&amp;是取址。

如果我定义了别的类,只需要类中有inter接口的那几个函数,我也可以直接使用接口的实例来调用类的方法。就好像,我先定义了各种鸟类,然后我发现它们可以抽象出统一的接口,于是我把它们的共同点抽象出来,成为一个接口。

go语言和c++最大的不同在于,它不需要使用基类。因为基类肯定定义在派生类之前,派生类还需要继承基类。如果基类设计的不好,那么整个代码调整起来就会很难,因为关联很多。它是一种总-分的结构,基类为总,然后分成各种派生类。

go则是反过来,是一种分-总的机构,原本是分,再是总。各种类可以随便写。接口可以在写完类后再定义。当然,有些东西该统一的还是需要统一的。不过,接口可以最后写,而不是c++那样,必须先有基类。这增加了不少灵活性。

感觉上,c++通过派生,把共同点派生出去。而go则是从原本的类中,提炼出共同点。

当然,c++并不是没有go的这种特性。因为重用的这部分是偏向逻辑的。c++中认为,逻辑的重用应该和类型无关,所以它直接把逻辑也给抽象掉了。提供了一个template,即模板。模板可以直接支持各种类型。其实和go的interface最对应的应该是模板。类的继承和操作符重载是为了让模板更方便使用(因为只有有了共同点,我们才能抽象出来)。因此c++中就没有接口这种说法。

以上是我对接口的理解。不知道对不对,如有错误望不吝赐教。

继续阅读