重写又叫覆盖,就是将从父类继承下来的属性或方法重新“定义”——就是重新写。
前面楠神讲过:
A类继承了B类,会把B类的一些属性和方法继承过来,都有哪些属性和方法会被继承?子类没有同名的属性和方法,并且访问修饰符不是private的会被继承下来。
我们现在重新理解这句话:
A类继承了B类,会把B类的一些属性和方法继承过来,都有哪些属性和方法会被继承?访问修饰符不是private的会被继承下来,但B类属性和方法会被A类同名的属性和方法覆盖掉。
重写的概念不难理解,重写的一些基本要求:
访问控制权限:
下级的访问控制权限应该不低于上级的访问控制权限:
上级:public 下级:只能public
上级:protected 下级: protected, public
上级:private 下级:private protected public——实际此情况无意义。
私有的不能覆盖,而是完全当作自己全新的。
方法的参数形式:
应该跟父类的一致。少了不行,多了也不行。
额外说明:
私有属性和私有方法的重写问题:私有属性和方法都不能覆盖,但其实子类可以定义跟父类私有的同名属性或方法。只是当作一个自身的新的属性或方法来看待而已。不过方法的参数必须一致。
构造方法的重写问题:构造方法不但可以像其他普通方法一样重写,而且,比普通方法更宽松:①重写的时候参数可以不一致,②访问控制权限可以低于父级的访问控制权限。
重点:
看如下的代码:
class Father {// 父类 private $num = 10; public function showFather() { echo $this->num; } } class Son extends Father { //子类 public function showSon() { echo $this->num; } } $son = new Son(); $son->showFather(); $son->showSon();
运行结果是这样的:
说明:
子类调用showFather方法,showFather方法是父类的公开方法,子类可以继承,在这种情况下,子类是可以通过父类的showFather方法获取到父类的私有属性$num的。
子类调用showSon方法,由于showSon方法是子类自己的方法,而父类的成员属性$num是私有的,子类无法继承,所以子类没有$num成员变量,showSon方法获取$num成员变量失败报错。
再看下面几种情况:
子类父类同时有成员变量$num,修饰符不一样,最终获取的值是怎么样的:
class Father {// 父类 private $num = 10; public function showFather() { echo $this->num; } } class Son extends Father { //子类 private $num = 20; public function showSon() { echo $this->num; } } $son = new Son(); $son->showFather(); echo '<br />'; $son->showSon();
现象①:父类子类成员变量都私有,子类对象调用父类方法获取的是父类成员变量,子类方法获取的是子类成员变量。⇧
class Father {// 父类 private $num = 10; public function showFather() { echo $this->num; } } class Son extends Father { //子类 protected $num = 20; public function showSon() { echo $this->num; } } $son = new Son(); $son->showFather(); echo '<br />'; $son->showSon();
现象②:父类成员变量私有、子类成员变量非私有,子类对象调用父类方法获取的是父类成员变量,子类方法获取的是子类成员变量。⇧
class Father {// 父类 protected $num = 10; public function showFather() { echo $this->num; } } class Son extends Father { //子类 protected $num = 20; public function showSon() { echo $this->num; } } $son = new Son(); $son->showFather(); echo '<br />'; $son->showSon();
现象③:父类子类成员变量都非私有,子类对象调用父类方法、子类方法都获取的是子类成员变量。⇧
class Father {// 父类 public function showFather() { echo $this->num; } } class Son extends Father { //子类 private $num = 20; public function showSon() { echo $this->num; } } $son = new Son(); $son->showFather(); echo '<br />'; $son->showSon();
现象④:父类没有成员变量,子类成员变量私有,子类对象调用父类方法访问子类私有成员变量会报错。⇧
class Father {// 父类 public function showFather() { echo $this->num; } } class Son extends Father { //子类 protected $num = 20; public function showSon() { echo $this->num; } } $son = new Son(); $son->showFather(); echo '<br />'; $son->showSon();
现象⑤:父类没有成员变量,子类成员变量非私有,子类对象调用父类方法是可以访问到子类的非私有成员变量的。⇧
总结:
子类对象调用自己的方法访问成员变量,
如果子类有成员变量,就访问子类自己的;
如果子类没有成员变量,可继承父类的就访问父类的。
子类对象调用父类的方法访问成员变量,
子类没有则访问父类的成员变量;
父类没有则访问子类的非私有成员变量;
子类父类都有成员变量,父类成员变量私有,访问的是父类的。父类成员变量非私有,访问的是子类的。
把 成员变量$num 改成 成员方法num() 效果是一样的。
把子类、父类的 shou方法 改成 静态方法 来调用,效果也是一样的。