golang的父子类函数重载
首先声明一点golang没有传统面向对象语言的父子类关系,golang使用struct来定义数据类型,通过匿名成员的关系模拟父子类关系;所以这里说的父子类是便于对照c++/java语言的类型概念,便于讲述和理解。
- 定义
我们先定义父子类关系;
父类: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")
}
- 验证重写功能
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。
- 子类里面如何调用父类的函数
func (n *C) Hello() {
n.A.Hello()
fmt.Println("in C::Hello")
}
func main() {
vc := &C{}
vc.Hello()
}
运行结果:
in A::Hello
in C::Hello
可见其语法是显示的指定父类的名。
- 虚函数
要说明虚函数,我们先定义一个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
和我们预想的一样。
- 父类指针指向子类
在传统面向对象语言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啊。
网友评论