Golang 继承和方法覆盖

use*_*847 0 inheritance overriding go

澄清:我刚刚学习 GO,遇到了这个问题。

我正在尝试实现一个继承一个方法的“类”,该方法调用应该由子类实现的“虚拟”方法。这是我的代码:

https://play.golang.org/p/ysiaPwARkvl

package main

import (
    "fmt"
    "sync"
)

type Parent struct {
  sync.Mutex
  MyInterface
}

func (p *Parent) Foo() {
  p.Lock()
  defer p.Unlock()
  p.Bar()
}

func (p *Parent) B(){
  panic("NOT IMPLEMENTED")
}

func (p *Parent) A() {
  p.Lock()
  defer p.Unlock()
  p.B()
}

type MyInterface interface {
  Foo()
  Bar()
}

type Child struct {
  Parent
  Name string
}

func (c *Child) Bar(){
  fmt.Println(c.Name)
}

func (c *Child) B(){
  fmt.Println(c.Name)
}

func main() {
  c := new(Child)
  c.Name = "Child"
  // c.A() panic
  c.Foo() // pointer error
}
Run Code Online (Sandbox Code Playgroud)

我遗漏了一些关于对 Child 的值进行异步更新的 sync.Mutex 的代码。

所以显然在 A() 或 Foo() 中,指针 p 的类型为 Parent。我应该如何更改我的代码,以便 A/Foo 引用 Child 类中定义的 B/Bar?

小智 5

当 Go 仅提供has-a关系(组合)时,您需要is-a关系(继承):

  • Go 没有继承,因此两种类型之间没有is-a关系。 Child不是一种Parent,所以指向 a 的指针Parent不能保留指向 a 的指针ChildChild has-a Parent包含在其中。

因为and之间没有is-a关系,不能接收 type 的对象,也不能使用任何实现的方法。此外,这意味着不能访问诸如或直接定义的任何方法。ParentChildParent.FooChildChildParentChildBar()B()

通常,Parent不需要在Child. 如果是,您将向该Parent方法传递一个参数,例如Child满足您通过接口调用该方法的接口或调用该Child方法的闭包:

// Use of an interface that Child satisfies.
type Beta interface {
    B()
}
func (p *Parent) A(b Beta) {
    p.Lock()
    defer p.Unlock()
    b.B()
}

// Use of a closure.
func (p *Parent) Foo(bar func()) {
    p.Lock()
    defer p.Unlock()
    bar()
}
func callFoo(p *Parent, c *Child) {
    callBar := func() {
        c.Bar()
    }
    p.Foo(callBar)
}

func (c *Child) Bar() {
    // stub
}

func (c *Child) B() {
    // stub
}
Run Code Online (Sandbox Code Playgroud)

Child可以Parent免费获得can call方法行为,但它只是看起来与继承相似。child.Foo()实际上执行child.Parent.Foo(),这意味着Parent.Foo仍然接收一个Parent实例(因此得名),而不是一个Child实例。

然而,Parent关于不能访问任何信息,ChildChild没有明确的份额。接口和闭包可以作为两个类之间的机制,类似于friendC++ 中的关键字,但它们比friend关键字更具限制性。毕竟,Child不需要与 共享所有内容Parent,只需要共享它想要共享的位,有点类似于C++ 中的这种模式。就我个人而言,我更喜欢这个接口,因为它允许你的Parent“类”处理多种类型,这些类型都满足一个公共接口,这使得它与从普通函数或完全不相关的类型方法调用方法几乎相同。