#delphi #polymorphism
Вопрос:
У нас есть приложение, которое довольно широко использует TIniFile. В прошлом мы создали наш собственный класс-потомок, назовем его TMyIniFile, который переопределяет запись. Мы создаем один экземпляр этого, который использует все приложение. Этот экземпляр передается повсюду через свойства и параметры, но тип всего этого по-прежнему является TIniFile, поскольку это то, чем он был изначально. Похоже, это работает, вызывая наш переопределенный метод с помощью полиморфизма, хотя все типы переменных все еще являются крошечными. Это кажется правильным, так как мы происходим из TIniFile.
Теперь мы вносим некоторые изменения, в которых мы хотим переключить TMyIniFile на потомок TMemIniFile вместо TIniFile. Оба они являются потомками TCustomIniFile. Мы также, вероятно, переопределим еще несколько методов. Я склонен оставить все объявления как TIniFile, хотя технически наш класс больше не является его потомком, просто чтобы избежать необходимости изменять много исходных файлов, если мне это не нужно.
В каждом учебном примере полиморфизма переменная объявляется как базовый класс, создается экземпляр класса-потомка и присваивается переменной базового класса. Поэтому я предполагаю, что это «правильный» способ сделать это. То, что я собираюсь сделать сейчас, приведет к тому, что переменные будут объявлены как, я думаю, вы бы назвали «родственным» классом, так что это «кажется неправильным». Разве это плохо, что ты так поступаешь? Я напрашиваюсь на неприятности или полиморфизм действительно допускает такие вещи?
Комментарии:
1. Объявить все ваши переменные как TMyIniFile-это правильный способ
Ответ №1:
TIniFile
и TMemIniFile
являются различными классами, которые не являются производными друг от друга, поэтому вы просто не можете создать TMemIniFile
объект и назначить его TIniFile
переменной, и наоборот. Компилятор не позволит вам этого сделать. И использование приведения типа для принудительного выполнения будет опасным.
Вам просто нужно будет обновить остальную часть кода, чтобы изменить все TIniFile
объявления на TCustomIniFile
вместо, что является общим предком для обоих классов. Это «правильное» решение.
Комментарии:
1. Если вы всегда создаете экземпляр TMyIniFile, то, на мой взгляд, вы должны объявить все переменные как TMyIniFile. От того, что вы предлагаете, ничего не выиграешь, и это просто запутывает код.
2. @DavidHeffernan Я придерживаюсь противоположного мнения. Все переменные должны быть TCustomIniFile, потому что именно там сначала отображается функция WriteString (), и коду не нужно знать подробности того, как реализована функция WriteString (). Если в будущем коду потребуется снова изменить реализацию, это будет легче сделать, если все переменные будут базовым классом, а не конкретным производным классом. Это также позволяет переносить код из одного конкретного класса в другой в более гибкие временные рамки.
Ответ №2:
Компилятор — ваш друг-зачем вам лгать ему, используя неправильный тип … и если вы действительно лжете ему, почему вы ожидаете, что он будет знать, чего вы хотите от него?
Вы должны использовать базовый класс, из которого вы производны, например TCustomIniFile
. Я ожидал бы проблем с компиляцией, если вы пытаетесь выполнить задания, которые, как известно, во время компиляции являются неправильными.
Разные классы имеют разные сигнатуры, поэтому компилятору необходимо знать, какой класс он использует, чтобы вызвать правильный метод или получить доступ к правильному свойству. С помощью виртуальных методов различные классы настраивают свою собственную реализацию этих методов так, чтобы вызывался правильный, поэтому при вызове виртуального метода используется указатель на базовый тип, который вызывает этот метод в производном типе, потому что он находится в таблице классов.
Поэтому, если код действительно компилируется, очень вероятно, что компилятор будет поступать неправильно …