PHP面向对象继承问题 - 开源中国

开源问答 技术问答

正文

PHP面向对象继承问题

Tommy-TFP 发布于 2018/06/13 13:49

阅读 231

收藏 0

答案 2

补充话题

开发四年只会写业务代码,分布式高并发都不会还做程序员?->>>   

class A {
    private function foo() {
        echo 'a';
    }
    public function test() {
        $this->foo();
    }
}
class B extends A {
    public function foo() {
        echo 'b';
    }
}
$b = new B();
$b->test();

这个结果是a,如果父类的foo方法是protected的,则结果为b,为什么?

收藏 (0)

分享

微博 QQ 微信

举报

加载中

最多投票 最新

0

[

tcxu

](https://my.oschina.net/tcxu)

tcxu

2018/06/13 15:50

知识要点: 
this,self,parent 三个关键字:

  1. 从字面上来理解,分别是指这、自己、父亲。
  2. this是指向当前对象的指针(可以看成C里面的指针),
  3. self是指向当前类的指针,
  4. parent是指向父类的指针

PHP中private和public还有protected的区别

  1. 冠有访问修饰符 provite 的方法,只能由本类的函数调用(call)。
  2. 冠有访问修饰符 protected 的方法,可以由本类或其子类的函数调用(call)/重写(或称覆盖 overwritten)

讨论
1.   问:为什么 类 A 的 foo()函数冠以 private,输出结果就是 a?
答:执行 $b->test(); $b 是 A 类的子类的对象,它调用的是 父类(A)的 public 函数test()。这个 A 类的函数test() 调用了同类的 private 函数 foo(), 故输出了a。就这个场合 (private function foo())而论,父类 A 中 public function test(){...}的代码,无论写成 self::foo();$this->foo(); 效果都一样
2..    问:为什么 类 A 的函数冠以 protected ,输出结果就是 b?
答: 鉴于冠以访问修饰符 protected的函数, 允许子类调用/重写,B类就重写了函数 foo()。执行 $b->test(); $b 是 A 类的子类的对象,它调用的是 父类(A)的 public 函数test()。此函数的代码的引用,this, 指向当前对象(即类B的对象 $b)的指针,这个指针指向在子类 B里 被重写的函数, 自然输出是 b 。
3.     问:如果既要输出 a,又要输出 b 该如何书写?

仅在子类 B 里覆盖的函数 foo()里添加一行代码即可:

parent::foo();

即:

<?php
class A {
    protected function foo() {
        echo 'a';
    }
    public function test() {
        $this->foo(); 
    }
}
class B extends A {
    public function foo() {
        parent::foo();
        echo 'b';
    }
}
$b = new B();
$b->test();
?>

评论 (2) 引用此答案 举报

[

tcxu

](https://my.oschina.net/tcxu)

tcxu

2018/06/17 09:58

回复 @Tommy-TFP : 谢谢你的回复。不过,你提出的这个PHP 继承问题,并非PHP 所固有的特殊情况。因此,我又专门发了一个帖子,如下。例举 JAVA,C++,JavaScript,Python的相同案例。请你再考虑一下。

回复 举报

[

T

](https://my.oschina.net/u/3885588)

Tommy-TFP

2018/06/16 00:50

你说的我都懂,关键在于为什么,没人说的清楚。除非看PHP源代码。这个问题就当做一个特殊情况吧,不过还是谢谢了。

回复 举报

0

[

tcxu

](https://my.oschina.net/tcxu)

tcxu

2018/06/16 18:04

父类 A 的公有成员函数/方法 定义为:

public function test() {
        $this->foo(); 
    }

这里,专门就这个指针 this 作以下三点说明。

  1. 这里,方法 foo()是同类(父类 A )的另一个成员方法。何种场合,允许或不允许它被子类覆盖/重写?何种场合应当调用哪里的 foo()?这是OOP 程序设计的一个重要方面,叫做 多态(polymorphism)
  2. 如果 foo() 的访问修饰符是 private (或 final),那么“任何时候”,指针 this 都指向这个唯一的 private foo()。“任何时候” 是指,往后若 A 的子类也定义了一个同名的 foo()方法。此时,子类定义的 foo() 方法,虽然同名,又完全合法 , 然而,它只是子类 B 新定义的一个方法,这个新方法与其父类的 private foo() 无任何关系,更与父类公有成员方法 test() 代码里的指针 this 无缘。记住: 冠以 private/final 的成员方法,不允许被子类覆盖/重写。
  3. 如果 foo() 的访问修饰符是 protected、无修饰符(表示同一个文件夹内有效), 或 public, 指针 this 则指向 “更新” 了的 foo()。“更新” 指它(foo())被子类覆盖/重写了。当然,如果它未被“更新”, 指针 this 仍旧指向父(A)类的成员方法 foo()。

这个问题并非 php 的特殊情况,一般具有 OOP 编程功能的计算机语言,如 Java、C++、python、JavaScript .... ,想必都会这样设计,案例如下。

java:

class A {
    protected void foo(){
        System.out.println('a');
    }
    public void test(){
        foo();
    }
}
class B extends A {
    public void foo(){
        System.out.println('b');
    }
}
public class AB {
    public static void main(String args[]){
        B b = new B();
        b.test();
    }
}

输出:

b

C++:

注解:virtual是C++ OOP 机制中很重要的一个关键字。只要是学过C++的人都知道在基类 A 中加了virtual关键字的函数就是虚拟函数(例如函数 foo()),于是在基类 A 的派生(子)类 B 中就可以通过重写虚拟函数来实现对基类虚拟函数的覆盖。这样一来,当基类 A 的派生类 B 的对象调用 test(),而 test() 进而又 调用函数 foo() 时,实际调用的是,被 B 类 覆盖(重新写)了的函数 foo(), 而不是 基类 A 原有的 函数 food() 。这便是面向对象程序设计中关于继承的一个律法。

#include <iostream>
using namespace std;
 class A {
     protected: 
    virtual void foo(){
        cout<<'a'<<endl;
    }
    public: 
    void test(){
        this->foo();
    }
};
class B : public A {
    public: 
    void foo(){
        cout<<'b'<<endl;
    }
};
int main(){
    B b ;
    b.test();
}

输出:

b

python:

class A:
    def food(self):
       print('a')
    def test(self):
        self.food()
class B(A):
     def food(self):
       print('b')
b = B()
b.test()

输出:

b

JavaScript:

<script>
function A(){    //类 A
    this.food = function(){
        alert('a');
    }
    this.test = function(){
        this.food();
    }
}
function B(){ //类 B
    this.food = function(){
        alert('b');
    }
}
B.prototype = new A();//B 继承 A
var b = new B(); //创建B类的对象
b.test();//调用其 父类的方法 test()
</script>

输出:

评论 (0) 引用此答案 举报

我要回答

操作提示

此操作将会扣除1积分,是否继续?

取消

确定

标记为最佳答案

确定将该答案采纳为最佳答案吗?

取消

确定

取消最佳答案

确定取消该最佳答案吗?

取消

确定


Original url: Access
Created at: 2019-04-19 09:58:21
Category: default
Tags: none

请先后发表评论
  • 最新评论
  • 总共0条评论