golang的父子类函数重载

首先声明一点golang没有传统面向对象语言的父子类关系,golang使用struct来定义数据类型,通过匿名成员的关系模拟父子类关系;所以这里说的父子类是便于对照c++/java语言的类型概念,便于讲述和理解。

  1. 定义

我们先定义父子类关系;
父类:A,定义了函数func Hello()
子类:B,简单继承了A
子类:C,简单继承了A,但重写了Hello()函数

代码如下:

type A struct {
   a int
}

func (n *A) Hello() {
    fmt.Println("in A::Hello")
}

type B struct {
   A
   b int
}

type C struct {
   A
   c int
}

func (n *C) Hello() {
    fmt.Println("in C::Hello")
}
  1. 验证重写功能
func main() {
    va := &A{}
    vb := &B{}
    vc := &C{}
    va.Hello()
    vb.Hello()
    vc.Hello()
}

运行:

in A::Hello
in A::Hello
in C::Hello

可见子类B并没有重写Hello函数,所以调用的实际上是A的函数;而类C重写了Hello。

  1. 子类里面如何调用父类的函数
func (n *C) Hello() {
    n.A.Hello()
    fmt.Println("in C::Hello")
}

func main() {
    vc := &C{}
    vc.Hello()
}

运行结果:

in A::Hello
in C::Hello

可见其语法是显示的指定父类的名。

  1. 虚函数

要说明虚函数,我们先定义一个Interface

type I interface {
    Hello()
}

这样前面的struct,A,B,和C都符合interface I的申明。

func foo(i I) {
  i.Hello()
}

func main() {
    va := &A{}
    vb := &B{}
    vc := &C{}
    foo(va)
    foo(vb)
    foo(vc)
}

运行结果:

in A::Hello
in A::Hello
in C::Hello

和我们预想的一样。

  1. 父类指针指向子类

在传统面向对象语言C++/Java里面我们经常会写类似函数,它使用一个父类指针作为参数,然后带使用的时候,可以传入父类的实例,或者子类的实例,然后在函数内用动态类型检测,比如dynamic_cast,来觉得传入的是父类还是子类。
还是以前面例子来说:C++版本:

#include <stdio.h>

class A {
public:
    virtual void Hello() { printf("in A::Hello\n"); }
};

class B : public A {
};

class C : public A {
public:
    virtual void Hello() { printf("in C::Hello\n"); }
};

void foo(A *p) {
    p->Hello();
}

int main(int argc, char * argv[]) {
    A * va = new A();
    B * vb = new B();
    C * vc = new C();
    foo(va);
    foo(vb);
    foo(vc);
}

编译运行:

in A::Hello
in A::Hello
in C::Hello

很好啊,然后golang是否有同样的功能呢?

func foo(v *A) {
  v.Hello()
}

func main() {
    va := &A{}
    vb := &B{}
    vc := &C{}
    foo(va)
    foo(vb)
    foo(vc)
}

编译:

# command-line-arguments
./main.go:43:8: cannot use vb (type *B) as type *A in argument to foo
./main.go:44:8: cannot use vc (type *C) as type *A in argument to foo

编译就出错了,golang根本就不认B/C和A是父子继承关系,golang认为A,B,和C是三种完全不同的数据类型,他们没有任何关系。

所以在golang里面是没有父类,子类这种概念关系的,所有的struct都是各自独立的,对于象:

type B struct {
   A
   b int
}

对于这种匿名成员关系,golang认为是内部的包含,而不是父子类关系。
那么golang如何实现抽象呢?答案就是用interface啊。