• [go学习笔记.第十章.面向对象编程] 9.面向对象的三大特性-继承


    1.看一个问题,引出继承的必要性

    1. package main
    2. import (
    3.     "fmt"
    4. )
    5. //编写一个学生考试系统
    6. type Pupil struct {
    7.     Name string
    8.     Age int
    9.     Score float64
    10. }
    11. //显示信息
    12. func (p *Pupil) showInfo() {
    13.     fmt.Printf("学生姓名:%v,年龄:%v,成绩:%v\n", p.Name, p.Age, p.Score)
    14. }
    15. //设置成绩
    16. func (p *Pupil) SetScore(s float64) {
    17.     //逻辑判断
    18.     p.Score = s
    19. }
    20. //考试状态
    21. func (p *Pupil) status() {
    22.     fmt.Println("正在考试")
    23. }
    24. // 大学生,高中生,...
    25. func main() {
    26.     p := &Pupil{
    27.         Name: "Jack",
    28.         Age: 11,
    29.         Score: 110.22,
    30.     }
    31.     p.status()//正在考试
    32.     p.SetScore(22)
    33.     p.showInfo()//学生姓名:Jack,年龄:11,成绩:22
    34. }

    对上面代码总结:

    1.Pupil和Graduate两个结构体字段和方法几乎一样,有很多相同的代码

    2.出现代码的冗余,而且代码不利于维护,同时也不利于功能的扩展

    3.解决方法:通过继承方式来解决

    2.继承的基本介绍和图示

    继承可以解决代码的复用,让编程更加靠近人类思维.

            当多个结构体存在相同的属性(字段)和方法时,可以从这些结构体中抽象出结构体,在该结构体中定义这些相同的属性和方法.

            其他结构体不需要重新定义这些属性(字段)和方法,只需要嵌套一个匿名结构体即可

    也就是说:

            在go语言中,如果一个struct嵌套了另一个匿名结构体,那么这个结构体可以直接访问匿名结构体中的字段和方法,从而实现继承特性

     3.嵌套匿名结构体的基本语法

    type Goods struct {

            Name string

            Proce int

    }

    type Book struct {

            Goods         // 这里就是嵌套匿名结构体Goods

            Writer string

    }

     4.案例

    1. package main
    2. import (
    3.     "fmt"
    4. )
    5. //因为小学生,大学生,高中生都有共有的属性和方法,故抽出来放到Student结构体中
    6. type Student struct {
    7.     Name string
    8.     Age int
    9.     Score float64
    10. }
    11. func (stu *Student) showInfo() {
    12.     fmt.Printf("学生姓名:%v,年龄:%v,成绩:%v\n", stu.Name, stu.Age, stu.Score)
    13. }
    14. //设置成绩
    15. func (stu *Student) SetScore(s float64) {
    16.     //逻辑判断
    17.     stu.Score = s
    18. }
    19. //编写一个学生考试系统
    20. // 小学生,大学生,高中生,...
    21. //小学生:
    22. type Pupil struct {
    23.     Student //嵌入了Student匿名的结构体
    24. }
    25. //考试状态:小学生结构体特有的方法,保留
    26. func (p *Pupil) status() {
    27.     fmt.Println("小学生正在考试")
    28. }
    29. //大学生:
    30. type Graduate struct {
    31.     Student //嵌入了Student匿名的结构体
    32. }
    33. //考试状态:大学生结构体特有的方法,保留
    34. func (g *Graduate) status() {
    35.     fmt.Println("大学生正在考试")
    36. }
    37. func main() {
    38.     //当对结构体嵌入了匿名的结构体时,使用的方法会发生变化
    39.     p := &Pupil{}
    40.     p.Student.Name = "jack"
    41.     p.Student.Age = 1
    42.     p.status()//小学生正在考试
    43.     p.Student.SetScore(90.01)
    44.     p.Student.showInfo()//学生姓名:jack,年龄:1,成绩:90.01
    45.     g := &Graduate{}
    46.     g.Student.Name = "Mary"
    47.     g.Student.Age = 23
    48.     g.status()//大学生正在考试
    49.     g.Student.SetScore(190.01)
    50.     g.Student.showInfo()//学生姓名:Mary,年龄:23,成绩:190.01
    51. }

    1. package main
    2. import (
    3.     "fmt"
    4. )
    5. //因为小学生,大学生,高中生都有共有的属性和方法,故抽出来放到Student结构体中
    6. type Student struct {
    7.     Name string
    8.     Age int
    9.     Score float64
    10. }
    11. func (stu *Student) showInfo() {
    12.     fmt.Printf("学生姓名:%v,年龄:%v,成绩:%v\n", stu.Name, stu.Age, stu.Score)
    13. }
    14. //设置成绩
    15. func (stu *Student) SetScore(s float64) {
    16.     //逻辑判断
    17.     stu.Score = s
    18. }
    19. //给Student增加一个方法,那么Pupil,Graduate都可以使用这个方法
    20. func (stu *Student) GetSum(n1 int, n2 int) int {
    21.     return n1 + n2
    22. }
    23. //编写一个学生考试系统
    24. // 小学生,大学生,高中生,...
    25. //小学生:
    26. type Pupil struct {
    27.     Student //嵌入了Student匿名的结构体
    28. }
    29. //考试状态:小学生结构体特有的方法,保留
    30. func (p *Pupil) status() {
    31.     fmt.Println("小学生正在考试")
    32. }
    33. //大学生:
    34. type Graduate struct {
    35.     Student //嵌入了Student匿名的结构体
    36. }
    37. //考试状态:大学生结构体特有的方法,保留
    38. func (g *Graduate) status() {
    39.     fmt.Println("大学生正在考试")
    40. }
    41. func main() {
    42.     //当对结构体嵌入了匿名的结构体时,使用的方法会发生变化
    43.     p := &Pupil{}
    44.     p.Student.Name = "jack"
    45.     p.Student.Age = 1
    46.     p.status()//小学生正在考试
    47.     p.Student.SetScore(90.01)
    48.     p.Student.showInfo()//学生姓名:jack,年龄:1,成绩:90.01
    49.     result := p.Student.GetSum(10, 20)
    50.     fmt.Println(result)
    51.     g := &Graduate{}
    52.     g.Student.Name = "Mary"
    53.     g.Student.Age = 23
    54.     g.status()//大学生正在考试
    55.     g.Student.SetScore(190.01)
    56.     g.Student.showInfo()//学生姓名:Mary,年龄:23,成绩:190.01
    57.     result2 := g.Student.GetSum(110, 20)
    58.     fmt.Println(result2)
    59. }

    5.继承给程序带来了便利

    (1).代码的复用性提高了

    (2).代码的扩展性和维护性提高了

    6.继承的深入讨论

    (1). 结构体可以使用嵌套匿名结构体所有的字段和方法,即:首字母大写或者小写的字段,方法都可以使用

    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. type A struct {
    6.     Name string
    7.     age int
    8. }
    9. func (a *A) SayOk() {
    10.     fmt.Println("A SayOk", a.Name)
    11. }
    12. func (a *A) hello() {
    13.     fmt.Println("A hello", a.Name)
    14. }
    15. type B struct {
    16.     A
    17. }
    18. func main() {
    19.     var b B
    20.     b.A.Name = "Mary"
    21.     b.A.age = 10
    22.     b.A.SayOk()//A SayOk Mary
    23.     b.A.hello()//A hello Mary
    24. }

    (2).匿名结构体字段访问可以简化

    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. type A struct {
    6.     Name string
    7.     age int
    8. }
    9. func (a *A) SayOk() {
    10.     fmt.Println("A SayOk", a.Name)
    11. }
    12. func (a *A) hello() {
    13.     fmt.Println("A hello", a.Name)
    14. }
    15. type B struct {
    16.     A
    17. }
    18. func main() {
    19.     var b B
    20.     b.A.Name = "Mary"
    21.     b.A.age = 10
    22.     b.A.SayOk()//A SayOk Mary
    23.     b.A.hello()//A hello Mary
    24.     //上面的写法可以简化
    25.     b.Name = "Jack"
    26.     b.age = 20
    27.     b.SayOk()//A SayOk Jack
    28.     b.hello()//A hello Jack
    29. }

    对上面代码的说明:

    1).当我们直接通过 b 访问字段或方法时,其执行流程如下比如 b.Name 
    2).编译器会先看 b 对应的类型有没有 Name ,如果有,则直接调用 B 类型的 Name 字段 
    3).如果没有就去看 B 中嵌入的匿名结构体 A 有没有声明 Name 字段,如果有就调用,如果役有继续查找,如果都找不到就报错

     (3).当结构体和匿名结构体有相同的字段或者方法时,编译器采用就近访问原则访问,如希望访问匿名结构体的字段和方法,可以通过匿名结构体名来区分

    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. type A struct {
    6.     Name string
    7.     age int
    8. }
    9. func (a *A) SayOk() {
    10.     fmt.Println("A SayOk", a.Name)
    11. }
    12. func (a *A) hello() {
    13.     fmt.Println("A hello", a.Name)
    14. }
    15. type B struct {
    16.     A
    17.     Name string
    18. }
    19. func (b *B) SayOk() {
    20.     fmt.Println("B SayOk", b.Name)
    21. }
    22. func main() {
    23.     var b B
    24.     b.Name = "Linda"    //ok
    25.    
    26.     b.age = 30  //ok
    27.     b.SayOk()//b SayOk Linda
    28.     b.hello()//A hello
    29.     b.A.Name = "Tom"
    30.     b.hello()//A hello Tom
    31.     b.A.SayOk()//A SayOk Tom
    32. }

    (4).结构体嵌入两个(或多个)匿名结构体,如两个匿名结构体有相同的字段和方法(同时结构体本身没有同名的字段和方法),在访问时,就必须明确指定匿名结构体名字,否则编译报错

    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. type A struct{
    6.     Name string
    7.     age int
    8. }
    9. type B struct{
    10.     Name string
    11.     score float64
    12. }
    13. type C struct{
    14.     A
    15.     B
    16.     //Name string
    17. }
    18. func main()  {
    19.     var c C
    20.     //如果C没有Name字段,而A,B有Name,这时就必须通过指定匿名结构体名字区分
    21.     //c.Name报错,编译错误,这个规则对方法同样适用
    22.     // c.Name = "tom"   //error
    23.     // c.A.Name = "tom" //ok
    24.    
    25. }

    (5).如果一个 struct 嵌套了一个有名结构体,这种模式就是组合,如果是组合关系,那么在访问组合的结构体的字段或方法时,必须带上结构体的名字

    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. type A struct{
    6.     Name string
    7.     age int
    8. }
    9. //组合结构体
    10. type D struct{
    11.     a A//有名结构体
    12. }
    13. func main()  {
    14.     //如果D中是一个有名结构体,则访问有名结构体的字段时,必须带上有名结构体的名字,如:d.a.Name = "tom"
    15.     var d D
    16.     // d.Name = "Mary"//error: 结构体D中没有Name,里面有一个有名的结构体A
    17.     d.a.Name = "tom"    //ok
    18.    
    19. }

    (6).嵌套匿名结构体后,也可以在创建结构体变量(实例)时,直接指定各个匿名结构体字段的值

    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. type A struct{
    6.     Name string
    7.     age int
    8. }
    9. type B struct{
    10.     Name string
    11.     score float64
    12. }
    13. type C struct{
    14.     A
    15.     B
    16.     //Name string
    17. }
    18. //组合结构体
    19. type D struct{
    20.     a A//有名结构体
    21. }
    22. type Goods struct{
    23.     Name string
    24.     Price float64
    25. }
    26. type Brand struct{
    27.     Name string
    28.     Address string
    29. }
    30. type TV struct {
    31.     Goods
    32.     Brand
    33. }
    34. type TV2 struct {
    35.     *Goods
    36.     *Brand
    37. }
    38. func main()  {
    39.     // var c C
    40.     //如果C没有Name字段,而A,B有Name,这时就必须通过指定匿名结构体名字区分
    41.     //c.Name报错,编译错误,这个规则对方法同样适用
    42.     // c.Name = "tom"   //error
    43.     // c.A.Name = "tom" //ok
    44.    
    45.     //如果D中是一个有名结构体,则访问有名结构体的字段时,必须带上有名结构体的名字,如:d.a.Name = "tom"
    46.     var d D
    47.     // d.Name = "Mary"//error: 结构体D中没有Name,里面有一个有名的结构体A
    48.     d.a.Name = "tom"    //ok
    49.     //嵌套匿名结构体后,也可在创建结构体变量(实例)时,直接指定各个匿名结构体字段的值
    50.     tv := TV{Goods{"电视剧机", 110.22}, Brand{"华硕","四川"},}
    51.     fmt.Println("tv:", tv)
    52.     tv2 := TV{
    53.         Goods{
    54.             Name : "电视剧机",
    55.             Price : 110.22,
    56.             },
    57.          Brand{
    58.              Name : "华硕",
    59.              Address : "四川",
    60.             },
    61.         }
    62.     fmt.Println("tv2:", tv2)
    63.     tv3 := TV2{&Goods{"电视剧机", 110.22}, &Brand{"华硕","四川"},}
    64.     fmt.Println("tv3:", *tv3.Goods, *tv3.Brand)
    65.     tv4 := TV2{
    66.         &Goods{
    67.             Name : "电视剧机",
    68.             Price : 110.22,
    69.             },
    70.          &Brand{
    71.              Name : "华硕",
    72.              Address : "四川",
    73.             },
    74.         }
    75.     fmt.Println("tv4:" , *tv4.Goods, *tv4.Brand)
    76. }

    说明:

    1).如果一个结构体有int类型的匿名字段,就不能有第二个

    2).如果需要有多个int的字段,则必须给int字段指定名字

    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. type Monster struct{
    6.     Name string
    7.     Age int
    8. }
    9. type E struct{
    10.     Monster
    11.     int
    12.     n int
    13. }
    14. func main()  {
    15.     //演示匿名字段是基本数据类型
    16.     var e E
    17.     e.Name = "猪八戒"
    18.     e.Age = 12
    19.     e.int = 20
    20.     e. = 30
    21.     fmt.Println("e:",e)
    22. }

     7.多重继承

    一个struct嵌套了多个匿名结构体,那么该结构体可以直接访问嵌套的匿名结构体的字段和方法,从而实现了多重继承
    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. type Goods struct{
    6.     Name string
    7.     Price float64
    8. }
    9. type Brand struct{
    10.     Name string
    11.     Address string
    12. }
    13. type TV struct {
    14.     Goods
    15.     Brand
    16. }
    17. func main()  {
    18.     //嵌套匿名结构体后,也可在创建结构体变量(实例)时,直接指定各个匿名结构体字段的值
    19.     tv := TV{Goods{"电视剧机", 110.22}, Brand{"华硕","四川"},}
    20.     fmt.Println("tv:", tv)
    21.     tv2 := TV{
    22.         Goods{
    23.             Name : "电视剧机",
    24.             Price : 110.22,
    25.             },
    26.          Brand{
    27.              Name : "华硕",
    28.              Address : "四川",
    29.             },
    30.         }
    31.     fmt.Println("tv2:", tv2)

     多重继承细节说明:

            1).如嵌入的匿名结构体有相同的字段名或者方法名,则在访问时,需要通过匿名结构体类型名来区分

             2).为了保证代码的简洁性,建议大家尽量不使用多重继承

    [上一节][go学习笔记.第十章.面向对象编程] 8.面向对象的三大特性-封装 

    [下一节][go学习笔记.第十章.面向对象编程] 10.面向对象的特性-接口 

  • 相关阅读:
    Java项目:ssm赛事打分系统
    前端知识学习案例9-开发企业网站9-实现关于我们的部分2
    深度学习实战51-基于Stable Diffusion模型的图像生成原理详解与项目实战
    不要再抱怨项目资源不足了,这么办都能解决
    创新领航 | 竹云参编《基于区块链的数据资产评估实施指南》正式发布!
    如何设置CUDA Kernel中的grid_size和block_size?
    基于小波分析与深度学习的脑电信号分类(matlab)
    linux- socket编程-直接获取网卡-packet- sokcket
    OpenHarmony网络协议通信c-ares [交叉编译]异步解析器库
    ArcGIS Pro地图可视化—双变量关系映射
  • 原文地址:https://blog.csdn.net/zhoupenghui168/article/details/125881381