对于golang

Go语言不支持继承,但支持组合.面向对象语言继承中的部分功能,可以使用组合来近似实现.

组合由结构体嵌套结构体来实现.

假设有两个结构体--- 作家author(“父类”)和作品work(“子类”),两结构体字段如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

type author struct {
name string //作者名
nationality string //国籍
gender string
age int
work //匿名(或者称为内嵌)字段,即该字段没有显式的名字。仅指明字段的类型,此时该类型就是字段的名字。切片类型在嵌套结构体时不能匿名,但结构体类型在嵌套结构体时可以匿名
}

type work struct {
name string //作品名
category string //作品类型
completedYear int //完笔年份
}
author结构体的字段有name, nationality, gender, age, 同时嵌套一个匿名结构体work。该字段表明author结构体是由work结构体组合而成。

则现在结构体author可以访问work结构体的所有成员和方法。声明一个work类型的变量w,再声明一个author类型的变量a;


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var w work
w.name = "战争与和平"
w.category = "masterpiece"
w.completedYear = 1869

//等同于
//w := work{
// name:"战争与和平",
// category:"masterpiece",
// completedYear:1869,
//}

var a author
a.name = "托尔斯泰"
a.nationality = "俄国"
a.gender = "男"
a.age = 82
a.work = w

fmt.Printf("作者名为:%s,作品名为:%s", a.name, a.work.name)
fmt.Println("\n")

fmt.Println(a.category)
fmt.Println(a.work.category)


一旦一个结构体嵌套另外一个结构体,Go访问嵌套结构体成员时,就好像是在访问自己结构体成员。也就是说a.work.category可以用a.category来代替。

但当两个结构体都有一个相同字段时,如此处的name,则访问”子结构体”work中的name属性,需要a.work.category,中间的.work不能省却;

上述代码输出:

1
2
3
4
作者名为:战争与和平,作品名为:战争与和平

masterpiece
masterpiece





结构体的同名成员(字段)在嵌套时如此,那同名的方法呢?

见如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package main

import "fmt"

type author struct {
name string //作者名
nationality string //国籍
gender string
age int
work //匿名(或者称为内嵌)字段,即该字段没有显式的名字。仅指明字段的类型,此时该类型就是字段的名字。切片类型在嵌套结构体时不能匿名,但结构体类型在嵌套结构体时可以匿名
}

type work struct {
name string //作品名
category string //作品类型
completedYear int //完笔年份
}

func (aa author) printSomething() {
fmt.Println("我是作家")
}

func (ww work) printSomething() {
fmt.Println("我是著作")
}

func (ww work) tellYouSomething() {
fmt.Println("作者将“战争”与“和平”的两种生活、两条线索交叉描写,构成一部百科全书式的壮阔史诗。")
}

func main() {

var w work
w.name = "战争与和平"
w.category = "masterpiece"
w.completedYear = 1869

//等同于
//w := work{
// name:"战争与和平",
// category:"masterpiece",
// completedYear:1869,
//}

var a author
a.name = "托尔斯泰"
a.nationality = "俄国"
a.gender = "男"
a.age = 82
a.work = w

a.printSomething()

a.work.printSomething()

a.tellYouSomething()

a.work.tellYouSomething()
}


输出为:
1
2
3
4
我是作家
我是著作
作者将“战争”与“和平”的两种生活、两条线索交叉描写,构成一部百科全书式的壮阔史诗。
作者将“战争”与“和平”的两种生活、两条线索交叉描写,构成一部百科全书式的壮阔史诗。


可见对方法同样如此.

另注:

golang中的方法和函数与其他编程语言中的同名概念有所不同.官方定义是方法是包含了接收者的函数;

Golang 不是一个纯粹的面向对象的编程语言,它不支持类。因此通过在一个类型上建立方法来实现与 class 相似的行为。
同名方法可以定义在不同的类型上,但是 Golang 不允许同名函数。假设有两个结构体 Square 和 Circle。在 Square 和 Circle 上定义同名的方法是合法的。

更多可点击,尤其是其中”值接收者和指针接收者”值得一看



参考 :

Golang 入门 : 结构体(struct)

Golang教程第27节–组合取代继承

golang 组合 继承



#### 对于php


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class author {

var $name = "托尔斯泰" ;
var $nationality = "俄国";
var $gender = "男";
var $age = 82;

public function printSomething($one,$two){

echo "我是作家\n";
var_dump($one);
var_dump($two);
}

public function father(){
echo "我是父类中的方法\n";
}

}

class work extends author {

var $name = "战争与和平";
var $category = "masterpiece";
var $completedYear = 1869;

public function printSomething($one,$two){

echo "我是著作\n";
var_dump($one);
return "666";
}

public function children(){
echo "我是子类中的方法\n";
}

}


$cs = new work();

$cs->father();
$cs->children();

$cs->printSomething("shuang","hahaha");

echo $cs->name;
echo PHP_EOL;

```

输出结果为:


我是父类中的方法
我是子类中的方法
我是著作
string(6) “shuang”
战争与和平
`

总结:


对方法的调用:
$this->方法名();如果子类中有该方法则调用的是子类中的方法,若没有则是调用父类中的;

在子类内部,使用parent::则始终调用的是父类中的方法。


对变量的调用:
$this->变量名;如果子类中有该变量则调用的是子类中的,若没有则调用的是父类中的

思考:如上代码中,如何在只实例化子类而不实例化父类的前提下,也不修改和侵入子类代码的情况下,实现调用父类中的(被子类重写的)printSomething()方法?


另注:自PHP5.3之后,子类重写(override)父类方法时(即在子类中重新定义一个和父类中某方法同名的新方法),子类中这个新方法的形参和父类的形参个数必须一致(因为php是弱类型语言,所以对类型是否一致不要求),对返回值无要求;

(如上面代码中,如果class work中的printSomething方法只有一个参数即printSomething($one),则在运行时会报错:

Warning: Declaration of work::printSomething($one) should be compatible with author::printSomething($one, $two) in /Users/xxxx/xxx/xxx.php on line xx)

对于静态方法,情况类似

参考:

php面向对象的重写与重载

PHP类方法重写原则

php子类中如何调用父类中的变量和方法

php继承父类,子类和父类中都有同名方法,实例化子类,在父类中调用这个方法,调用的是子类的


不作总结,看这两段代码十分明晰了~