class theA{
public:
int X = 3;
};
class theB : public theA{
public:
int X = 5;
};
Конструкторы и проч. здесь опущены, равно и как само присваивание сделано наглядно для краткости, но синтаксически неправильно. Я, в конце-концов, иллюстрирую проблему, найденную в PHP Если
class theA * ptrA = new theA();
class theB * ptrB = new theB();
то ptrA->X == 3, а ptrB->X == 5. При этом не запрещено и по указателю ptrB достучаться до того X, который равен 3. Надо только сказать, что ptrB следует считать указателем на theA. Это - совершенно корректно, поскольку theB - прямой наследник theA, делается это приведением типа: (theA)ptrB->X == 3, а ptrB->X как был, так и останется равным 5. Это - две разные переменные, они просто немного "затеняют" друг-друга, но не больше. Никаких проблем с пониманием к которой из них хочет обратиться программист у компилятора нет.
А вот в PHP такая штука не получается. Вот код:
<?php
class theA{
var $class_data ='theA';
public function ShowData(){ print $this->class_data."\n"; }
public function ShowMyData(){ print $this->class_data."\n"; }
}
class theB extends theA{
var $class_data ='theB';
public function ShowData(){ print $this->class_data."\n"; }
}
$ObjA = new theA();
$ObjB = new theB();
$ObjA->ShowData(); //1
$ObjA->ShowMyData(); //2
$ObjB->ShowData(); //3
$ObjB->ShowMyData(); //4
?>
Код выводит:
theA //1
theA //2
theB //3
theB //4
Почему 1 и 3 строчки отличаются нет удивления - это разные классы и разные $this, а названия методов - одинаковые ShowData. Поэтому одинаковая конструкция print $this->class_data; и выводит разные результаты. Так - правильно и так и ожидается. А вот почему отличаются строчки 2 и 4 - тайна сия велика есть. Поскольку в классе theB нету метода ShowMyData, то совершенно правильно, что вызывается метод из класса theA - для theB класс theA базовый. Но вот почему у этого метода к классу theA не приводится и его $this, а подставляется $this от класса, про который theA ничего не знает? Ведь в методе theA::ShowMyData с точки зрения правильного ООП $this то должен быть от "своего класса" без лишних напоминаний? Нету здесь "виртуализации" - метод не перегружен, не объявлен виртуальным и проч.
Ладно, допустим, что в данном случае все методы и данные - виртуальные по умолчанию. Но тогда как синтаксически явно сделать "лишнее напоминание", что $this надо взять от theA? Очевидная конструкция (theA)$this не канает - это синтаксическая ошибка.
При этом внутри метода theB::ShowData можно вызывать theA::ShowData, это делается так:
public function ShowData(){
parent::ShowData();
print $this->class_data."\n";
}
и в этом случае сначала отработает конструкция print $this->class_data из theA::ShowData(), а следом - print $this->class_data из самого theB::ShowData(). Но $this в обе будет подставлен интерпретатором один и тот же, т.е. вывод этого метода будет:
theB
theB
Как достучаться до theA::$class_data имея ptrB?
Занятно, то если $class_data объявлен статическим, то никаких трудностей не возникает - есть и работает каст из "оператора четыре точки", причём такой всякий разный, что в голову не придёт его во всех вариантах использовать, коль скоро язык просто позволяет глобальные переменные. А как привести _нестатический_ $this?
Исследование "магических методов" показало, что это те же вариации на тему либо "статического каста", либо синтаксически кривого вызова всё тех же методов относительно "просто $this", т.е. извращения программиста, как сделать то, что не умеет компилятор. Но сколько я не искал я не нашёл ответа на вопрос в заголовке темы.
Я буду очень признателен коллегам за, как говорят any ideas - начиная от простой ликвидации моей дремучести и кончая извращениями, как этот самый каст эмулировать руками. Потому, как эта возможность - один из столпов ООП и без неё получается архитектурно криво.