Go语言无法天然支持继承,但是又想要实现面向对象的特性。
即父类对象 使用子类对象初始化,那么该父类对象调用的函数就是子类实现的函数 ,从而满足LSP(子类交换原则)。
案例一: Go语言 支持扩展父类的功能,如下代码:
package oriented_testimport ("fmt""testing"
)// Pet 类
type Pet struct {
}func (p *Pet) Speak(){ // Pet类的函数成员fmt.Print("Pet speak.
")
}func (p *Pet) SpeakTo(host string) { // Pet类的函数成员p.Speak()fmt.Println("Pet SpeakTo ", host)
}// Dog 扩展Pet的功能
type Dog struct { p *Pet
}// 扩展父类的方法
func (d *Dog) Speak(){ d.p.Speak()
}// 扩展父类的方法
func (d *Dog) SpeakTo(host string) { d.Speak()fmt.Println("Dog Speakto ", host)
}func TestDog(t *testing.T) { dog := new(Dog)dog.SpeakTo("Test dog")
}
以上测试代码的输出如下:
Pet speak.
Dog Speakto Test dog
dog的SpeakTo中调用了dog 的Speak,其中调用了Pet的Speak,所以输出正常。
Pet 和 Dog调用不会相互影响,完全由用户决定。
但是这和我们所想需要的不同,Pet类有自己的方法,Dog类有自己的方法,两者作用域完全不同。
这里Go语言推出了匿名嵌套类型,即Dog类不用实现自己的和Pet类同名的方法即可,通过在Dog类的声明中变更Pet成员。
案例二: Go语言支持匿名函数类型
// Dog 扩展Pet的功能
type Dog struct { Pet
}
这样即不需要Dog声明自己的同名函数成员,默认的调用即为Pet成员函数的调用
package oriented_testimport ("fmt""testing"
)type Pet struct {
}func (p *Pet) Speak(){ fmt.Print("Pet speak.
")
}func (p *Pet) SpeakTo(host string) { p.Speak()fmt.Println("Pet SpeakTo ", host)
}// Dog 扩展Pet的功能
type Dog struct { Pet // 支持匿名嵌套类型,
}func TestDog(t *testing.T) { var dog Dogdog.Speak()dog.SpeakTo("Test dog")
}
最终的输出如下:
=== RUN TestDog
Pet speak.
Pet speak.
Pet SpeakTo Test dog
--- PASS: TestDog (0.00s)
调用的都是Pet的成员函数,感觉像是继承了,因为继承默认就是子类能够使用父类的公有成员。
在匿名嵌套类型下,我们想要完整尝试一下Go语言是否真正支持继承,可以像之前的代码一样在Dog中实现Pet的同名函数,且能够通过父类对象调用子类的成员方法,像C++/Java这样进行向上类型转换(本身是不可能的,Go语言不支持显式类型转换)。
案例三: Go语言不支持继承,如下代码:
package oriented_testimport ("fmt""testing"
)type Pet struct {
}func (p *Pet) Speak(){ fmt.Print("Pet speak.
")
}func (p *Pet) SpeakTo(host string) { p.Speak()fmt.Println("Pet SpeakTo ", host)
}// Dog 扩展Pet的功能
type Dog struct { //p *PetPet // 支持匿名嵌套类型
}// 重载父类的方法
func (d *Dog) Speak(){ fmt.Print("Dog speak.
")
}// 重载父类的方法
func (d *Dog) SpeakTo(host string) { d.Speak()fmt.Println("Dog Speakto ", host)
}func TestDog(t *testing.T) { var dog Pet = new(Dog)dog.Speak()dog.SpeakTo("Test dog")
}
在最后的输出会编译出错,不支持将Pet类型转换为Dog类型:
./oriented_test.go:38:6: cannot use new(Dog) (type *Dog) as type Pet in assignment
总结一下,Go语言并不支持继承,能够支持接口的扩展 和 复用(匿名嵌套类型)
其中扩展 就是不同类实现相同的成员函数,能够实现类似于案例一中的扩展接口形态。
复用则是通过匿名嵌套类型实现 类似于重载的功能,可以看看案例二的代码。
师弟总结的已经很好了 或者: 原工程需要导出的函数: extern "C" __declspec(dllexport) void Func(); 现工程导入这个函数: extern "C" __declspec(dllimport) void Func();...
有使用过JS的朋友,相信都知道function。JS中的function是可以在里面在定义一个作为内部使用的。有时为了控制作用域,或者这种小函数只在这个函数体内会使用,所以就不希望在外部在作额外的定义。那C#中有没有这样类似的方式呢?答案是有的。 在C#中要实现,需要用到的是委托和lambda表达式。对于lambda表达式,是可以实...