美文网首页
golang的父子类函数重载

golang的父子类函数重载

作者: CodingCode | 来源:发表于2020-02-23 09:34 被阅读0次

    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啊。

    相关文章

      网友评论

          本文标题:golang的父子类函数重载

          本文链接:https://www.haomeiwen.com/subject/empdqhtx.html