Виртуальным называют метод, который может переопределяться в производном классе. А в нашем случае функции show() и hide() являются виртуальными, и даже более того: в классе shape мы не знаем, как они должны быть "устроены", потому что у нас еще нет информации о типе фигуры. Таким образом, вызывать виртуальные методы shape бессмысленно.
Виртуальные методы базового класса, которые бессмысленно и даже запрещено вызывать непосредственно, называют абстрактными.
В базовом классе shape виртуальные методы show() и hide() "вырождены" и являются абстрактными, нам обязательно нужно переопределить их в производном классе.
<?php ## Производный класс: фигура-круг.
class Circle extends Shape {
private $radius;
// Создает новый объект-круг с указанием радиуса,
public function _construct($radius=100) {
$this->radius = $radius;
parent::_сonstruct();
}
// Отображает круг на экране.
public function show() {
list ($x, $y) = $this->getCoord();
$radius = $this->radius * $this->getScale();
echo "Рисуем круг: ($х, $у, $radius)<br>";
}
// Стирает фигуру с экрана,
public function hide() {
list ($x, $y) = $this->getCoord();
$radius = $this->radius * $this->getScale();
echo "Стираем круг: ($х, $у, $radius)<br>";
}
}
?>
1. Любой объект-круг является также и объектом-фигурой, а потому должен наследовать методы и свойства класса shape. Поэтому объявляем circle производным от Shape.
2. У круга, помимо свойств, присущих фигуре, есть и свои собственные данные: это его радиус. Создаем свойство $radius, в котором он будет храниться и объявляем его как private.
3. Круг имеет свой собственный конструктор, который вызывается в момент создания объекта. При создании указывается радиус круга. Фактически у каждого типа фигуры будут свои собственные конструкторы с различающимися списками параметров. Конструктор обычно не наследуется. НО мы обязательно должны вызвать конструктор базового класса shape, в противном случае фигура не будет проинициализирована( parent::_construct()).
В классе круг необходимо реализовать (переопределить) абстрактные функции show() и hide(). Они должны отображать круг на экране. Если в классе shape мы еще не имели информацию о том, как именно следует прорисовывать фигуру, то в классе circle это должно быть абсолютно ясно.
Виртуальный метод не обязательно должен быть абстрактным.
1. Абстрактный метод нельзя вызвать, если он не был переопределен в производном классе. Собственно, написав функцию shape:: show() и поместив в нее вызов die(), мы как раз и гарантируем, что она обязательно будет переопределена в производном классе (иначе получим ошибку во время выполнения программы).
2. Объект абстрактного класса невозможно создать.
3. Любой класс, содержащий хотя бы один абстрактный метод, сам является абстрактным.
Абстрактные классы можно использовать только для одной цели: создавать от них производные. Сделаем из shape абстрактный класс, добавив ключевое слово abstract там, где это необходимо по логике.
<?php ## Абстрактный класс — геометрическая фигура,
abstract class Shape {
private $x=0, $y=0, $scale=1.0;
public function _construct() {
$this->show();
}
public function _destruct() {
$this->hide();
}
public final function moveBy($dx, $dy) {
$this->hide();
$this->x += $dx;
$this->y += $dy;
$this->show() ;
}
public final function resizeBy($coef) {
$this->hide();
$this->scale *= $coef;
$this->show() ;
}
public final function getCoord() { return array($this->x, $this->y); }
public final function getScale() { return $this->scale; }
// Абстрактные методы,
abstract protected function hide();
abstract protected function show();
}
?>
При объявлении абстрактного метода (например, show()) не нужно определять его тело — просто поставьте точку с запятой после его прототипа.
Объекты производных классов допустимо использовать в том же контексте, что и объекты базовых, т.е. можно преобразовать circle в shape, но не наоборот.