Go父类调用子类方法(虚函数调用)

news2024/9/22 23:32:24

前言

在Go语言中,支持组合而不是继承。网上都说可以通过接口和结构体内嵌来模拟面向对象编程中的子类和父类关系。但给的例子或写法感觉都不是很好,难以达到我的目的(比如通过模板模式实现代码的重用等)。因此调查了一下实现方式。

结论

  • 可以通过定义 interface + 组合接口变量 + NewXxx 函数中对接口变量赋值(类似于给 this 变量赋值) 的方式实现 Go 的继承和虚函数调用。废话少说, 直接上代码。
// 定义一个表示形状的 Shape 接口
type Shape interface {
	Name() string
	Area() float64      //求面积
	Perimeter() float64 //求周长
	String() string
}

// 定义实现了部分业务逻辑的抽象基类
type BaseShape struct {
	Shape // 组合了接口,因此有了其接口的方法声明, 注意: 其值为 nil, 需要在子类的 NewXxx 中对其赋值(相当于设置为 this)
	name  string
}

func (bs BaseShape) Name() string {
	return bs.name
}

func (bs BaseShape) AbstractMethod() string {
	return "base"
}

// 此处在 BaseShape 的 String() 方法中调用子类会重载的 Area()/Perimeter() 方法
func (bs BaseShape) String() string {
	if bs.Shape == nil {
	    // 由于需要手动设置 Shape 的值(不像 C++ 可以在 new 时自动设置), 为了在 nil panic 的时候有更好的提示, 此处主动 panic,提醒这种编码错误
		panic(fmt.Sprintf("must set Shape in child struct 's new function, name=%s", bs.name))
	}
	//这里既可以通过 bs.Xxx() 调用, 也可以通过 bs.Shape.Xxx() 调用.
	return fmt.Sprintf("name=%s: absMethod=%s, area=%f, perimeter=%f",
		bs.Name(), bs.AbstractMethod(), bs.Shape.Area(), bs.Shape.Perimeter())
}

type Rect struct {
	BaseShape
	Width  float64
	Height float64
}

func (r *Rect) Area() float64 {
	return r.Width * r.Height
}
func (r *Rect) Perimeter() float64 {
	return 2 * (r.Width + r.Height)
}

func (r *Rect) AbstractMethod() string {
	return "abs_rect"
}

func NewRect(width, height float64) *Rect {
	rect := &Rect{
		BaseShape: BaseShape{name: "rect"},
		Width:     width,
		Height:    height,
	}
	rect.Shape = rect // 将 BaseShape 中的 Shape 变量设置为 this,父类才可以调用
	return rect
}

type Square struct {
	Rect
}

func NewSquare(sides float64) *Square {
	square := &Square{Rect{
		BaseShape: BaseShape{name: "square"},
		Height:    sides,
		Width:     sides,
	}}
	square.Shape = square
	return square
}
type Circle struct {
	BaseShape
	Radius float64
}

func (c *Circle) Area() float64 {
	return math.Pi * c.Radius * c.Radius
}
func (c *Circle) Perimeter() float64 {
	return 2 * math.Pi * c.Radius
}

func (c *Circle) AbstractMethod() string {
	return "abs_circle"
}

func NewCircle(radius float64) *Circle {
	circle := &Circle{
		BaseShape: BaseShape{name: "circle"},
		Radius:    radius,
	}
	circle.Shape = circle //将 BaseShape 中的 Shape 变量设置为 this,父类才可以调用
	return circle
}

以上代码实现了如下的继承结构,可以将 String() 方法看成业务方法,其中调用子类提供实现的抽象方法。
在这里插入图片描述

测试代码

通过 shape 变量的 String() 方法调用了子类的 Name()/Area()/Perimeter() 等方法.

func TestVirtualFunctionCall(t *testing.T) {
	var rect Shape = NewRect(10, 20)
	var circle Shape = NewCircle(10)
	var square Shape = NewSquare(10)

	assert.Equal(t, "name=rect: absMethod=base, area=200.000000, perimeter=60.000000", rect.String())
	assert.Equal(t, "name=square: absMethod=base, area=100.000000, perimeter=40.000000", square.String())
	assert.Equal(t, "name=circle: absMethod=base, area=314.159265, perimeter=62.831853", circle.String())
}

补充说明

  • 通过这种方法,可以成功的在 Go 语言中实现 多态,虚函数 等 C++/Java 才有的概念,从而可以想办法实现各种设计模式,大大提高项目质量。
  • 但也存在一些限制,比如:
    • 无法在 BaseShape 中再次定义一些虚函数由子类实现并调用(参考 AbstractMethod),如想要其也是虚函数的样子,必须也定义到 interface 中.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2101475.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内裤洗衣机需要一人一台吗?快来围观2024年五大好货集合

随着市面上的内衣抑菌产品越来越多,内衣洗衣机的质量也是参差不齐,一些网红跨界品牌内衣洗衣机的用料和做工品质较差,使用过程中出现清洗不干净和稳定性不足等问题。那么选购内衣洗衣机需要注意什么呢?我作为一名小家电测评博主&a…

pikachu文件包含漏洞靶场(本地文件包含+远程文件包含关卡)

本地文件包含 1.来到关卡随便点击一个提交 可以发现这里可以读取文件 这是1.txt内容 能读取到上一级文件那么也就可以读取本地文件 上传一个jpg文件 拿去连就ok了 远程包含 包含写木马的文件 该文件内容如下,其作用是在fi_remote.php文件的同级目录下新建一个文…

Java 基于微信小程序的小区服务管理系统,附源码

博主介绍:✌stormjun、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&…

【赵渝强老师】MongoDB的WiredTiger存储引擎

WiredTiger提供文档级别(Document-Level)的并发控制,检查点(CheckPoint),数据压缩和本地数据加密( Native Encryption)等功能。从MongoDB 3.2 版本开始,WiredTiger成为Mo…

大带宽服务器推流延迟怎么回事

大带宽服务器推流延迟的原因可能涉及多个方面,包括编码解码的延迟、网络传输延迟、CDN分发延迟以及播放端的缓冲处理等。下面将详细解释各个影响因素,并提出相应的优化建议: 1. 编码解码的延迟 视频编码格式的影响:不同的编码格式…

net、udp、tcp

Makefile的main.c文件中的全局变量SONG song,要在fun.c文件里面写成extern SONG song 编译方法 第一次编写 或 网络编程 物理层的网线规定有八根,颜色不一样,功能不一样,光猫把光信号转换成电信号,光纤10Gb WiFi叫无线局域网,一般也就50米左右,手机流量叫蜂窝网络,…

无限延展(倒推法)

本题不妨逆推。 对于长度为的字符串 ,若要求第位的延展,考虑 在最后一次延展前的位置。 若延展结束后的长度为,每次考虑以下内容: 若 ​,说明本次伸展无效, ,

CTFHub技能树-备份文件下载-bak文件

当开发人员在线上环境中对源代码进行了备份操作,并且将备份文件放在了 web 目录下,就会引起网站源码泄露。 使用dirsearch扫描出index.php.bak 有些时候网站管理员可能为了方便,会在修改某个文件的时候先复制一份,将其命名为xxx.b…

没关系,会一手Git版本控制就行(全)

Git版本控制 文章目录 Git版本控制1. 版本控制1.1 概述1.2 版本控制优点1.3 本地版本控制系统(离线版)1.4 集中化的版本控制系统(联网版)1.5 分布式版本控制系统(离线联网版) 2. Git概述2.1 Git基本工作流程…

BUUCTF PWN wp--ciscn_2019_n_8

第一步 checksec一下,本题为32位。 分析一下保护机制: 一、RELRO: Partial RELRO Partial RELRO 提供了一定程度的保护。在这种情况下,部分重定位表在程序启动时被设置为只读。这可以防止一些针对重定位表的攻击,比如通过篡改重…

Elasticsearch 介绍

1、课程介绍 1.1 ES 8.x 演化进程 版本号发布日期多少个次要版本迭代历时8.02022年2月11日?至今7.02019年4月11日17个次要版本34个月6.02017年11月15日8个次要版本17个月5.02016年10月27日6个次要版本13个月 2、Elasticsearch 是什么 2.1 概念 2.1.1 标准定义 …

QLineEdit中文本显示不全,部分字符显示空白问题

环境 QT5.14.2 Windows 7 现象 触发某个条件后,使用QLineEdit的setText方法设置文本后,文本部分字符缺失,现象如下(小数点后都是4位): 解决办法 设置根据显示器的像素密度进行自动缩放;再主…

VMware启动报错-Intel VT-x处于禁用状态,进入BIOS更改CPU设置

问题描述 VMware启动虚拟机失败,报错显示Intel VT-x处于禁用状态。 原因分析 打开主机的任务管理器,找到CPU,发现虚拟化处于禁用状态,查阅资料之后发现,进入BIOS模式将CPU虚拟化禁用开启即可解决。 解决步骤 1、…

KAN 学习 Day1 —— 模型框架解析及 HelloKAN

说明 最近了解到了一个新东西——KAN,我的毕设导师给推荐的船新框架。我看过很多剖析其原理的文章,发现大家对其持有的观点都各不相同,有的说可以颠覆传统MLP,有的说可以和Transformer同等地位,但是也有人说它训练速度…

15chatGLM3半精度微调

1 模型准备 数据依然使用之前的数据,但是模型部分我们使用chatglb-3,该模型大小6B,如果微调的话需要24*4 96GB,硬件要求很高,那么我们使用半精度微调策略进行调试,半精度微调有很多坑啊,注意别踩到…

只会SQL语句,可以做什么工作?

1、SQL是什么 首先简单介绍一下SQL(Structured Query Language),是一种可以进行数据提取、聚合、分析,并对数据库进行构建和修改的编程语言。 相对来说,SQL上手非常容易,因为语法结构比较固定&#xff0c…

第一性原理计算从定义到场景到硬件配置详细讲解

第一性原理计算,又称为从头计算(The Ab initio Calculation),是一种基于量子力学原理,通过计算机模拟来预测材料、分子、固体等体系性质的方法。这种方法的核心思想是不依赖于实验数据或经验参数,而是直接从…

如何纯手动的创建SpringBoot工程?

1、打开项目结构 2、new 一个新模块 3、所需全部选配好 4、 创建好之后,目录如下 5、在pom文件中,做第一件事情(让当前的工程继承一个父工程) (这是一个固定的写法:spring-boot-starter-parent)…

JavaWeb - Maven

Maven apache旗下的一个来源项目,一款用于管理和构建java项目的工具,它基于项目对象模型(POM)的概念,通过一小段描述信息来管理项目的构建。 作用 安装 解压官网下载的压缩包 配置本地仓库,修改conf/se…

接口请求400

接口请求400 在Web开发中,接口请求错误是开发者经常遇到的问题之一。其中,400错误(Bad Request)尤为常见,它表明发送到服务器的请求有误或不能被服务器理解。本文将深入探讨接口请求400错误,从常见报错问题…