0
- 16.06.2014 - 13:05
|
Всем добрый день. Столкнулся с необходимость перенести несложный код с Pascal на какой-нибудь Си-подобный язык. В целом, все ок, но осталась одна проблема - как я понял, в этих языках нельзя НЕ вызвать конструктор предка при создании потомка. А мне вот нужно. Рафинированный пример того, что хочется - на Паскале. program test ; **$mode objfpc****$h+** type TBase = class protected x:Integer ; flag:string ; public // Конструктор предка constructor Create(Ax:Integer) ; virtual ; procedure WriteInfo() ; end ; TBase2 = class(TBase) private public // Перекрываем конструктор в потомке constructor Create(Ax:Integer) ; override ; end ; constructor TBase.Create(Ax:Integer) ; begin x:=Ax ; flag:='OK' ; end ; procedure TBase.WriteInfo() ; begin Writeln(flag,' ',x) ; end ; constructor TBase2.Create(Ax:Integer) ; begin // Если условие, то вызываем конструктор, иначе - особая инициализация if Ax<10 then inherited Create(Ax) else x:=99 ; end ; begin TBase2.Create(2).WriteInfo() ; // Здесь будет вызван конструктор предка TBase2.Create(22).WriteInfo() ; // Здесь - уже нет end. Программа выводит, разумеется ОК 2 99 ибо конструктор предка во втором случае не вызывается. Быстрый поиск подобных вопросов показал, что для С++ это сделать невозможно. То есть, нечто вроде class TBase2 : public TBase ** public: TBase2(int Ax) ** TBase(Ax) ; ** ** ; недопустимо в принципе. Скажите, что это нельзя сделать также для С# и Java - тогда я решу проблему другим способом. Если же есть вариант, пусть даже технически извращенный - буду очень благодарен за подсказку. | |
1
- 16.06.2014 - 16:07
|
А что мешает if Ax<10 then ... else x:=99 ; в логику базового класса перенести? ====================== А вообще, в конструкторе базового класса можно проверить реальный тип объекта и при необходимости выполнить нужный блок кода (пример на C#): ------------- using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 ** class Program ** static void Main(string[] args) ** Cbase2 v_obj = new Cbase2(); Console.WriteLine("============"); CBase v_obj2 = new CBase(); Console.ReadKey(); ** ** class CBase ** public CBase() ** if (!(this is Cbase2)) ** Console.WriteLine("CBase Constructor"); ** else ** Console.WriteLine("CBase Dummy block executed"); **; ** ** class Cbase2 : CBase ** public Cbase2() ** Console.WriteLine("CBase2 Constructor"); ** ** ** ------------- | |
2
- 16.06.2014 - 16:13
|
Спасибо, думал об этом, но это не совсем то. public CBase() ** if (!(this is Cbase2)) ** Получается, что базовый класс должен знать что-то о потомке - это еще хуже для логики. А если потомков штук 10? То, что исходная задача скорее всего возникла из-за кривой архитектуры классов - очевидно, но всё-таки, Pascal мне эту возможность прострелить ногу предоставляет. А С++, походу, нет. | |
3
- 16.06.2014 - 16:22
|
Именно "прострелить ногу". В паскале легко "забыть" про необходимость вызова базового конструктора в конструкторе потомка. И получить неполноценно инициализированный объект просто из-за забывчивости. А в сях, чтобы получить "неполноценный" объект, нужно специально писать соответсвующий код в базовом классе. Т.е. ты на 100% знаешь что делаешь. ИМХО так... | |
4
- 16.06.2014 - 16:27
|
Паскаль дает пистолет и говорит - делай что хочешь, попадешь в ногу - сам виноват. С дает пистолет, но при этом, чтобы выстрелить в ногу, нужно на этом пистолете осознано переключить большой красный переключатель в режим "выстрел в ногу". | |
5
- 16.06.2014 - 16:50
|
Угм, примерно так и думал. Значит, просто перепишу логику и не буду мучить С++ с Явой странными хотелками. PS: Паскаль обычно наследует конструктор по умолчанию. В общем случае, это ещё лучше и проще, чем обязательное прописывание в С++ TBase2(int Ax) : TBase(Ax) **** ; | |
6
- 16.06.2014 - 21:44
|
В общем случае если нужно в потомке сделать особую инициализацию, то в java используется метод, который вызывается в конструкторе родителя, и по необходимости определяется в потомке, но это плохое решение. лучшее надо смотреть от задачи. | |
7
- 23.06.2014 - 09:27
|
0-NTFS_ > Какое-то хреновое ООП =) Проверка в родительском конструкторе на вызов для создания объекта другого класса не подойдет? if (!this.getClass().equals(Parent.class)) ? | |
8
- 23.06.2014 - 11:31
|
7-40KHYTbIU > Проверка в родительском конструкторе на вызов для создания объекта другого класса не подойдет? Подойдет, конечно, но это означает, что родитель должен знать что-то о своих потомках. Проблему решил, просто выкинул весь код с хитрым наследованием и поставил фабрику. Это заняло 10 минут кодирования и 20 минут объяснений заказчику, что это за странное колдовство с вводом нового класса :-) | |
9
- 24.06.2014 - 00:17
| Конструктор родителя может проверить класс вызвавшего объекта на равенство своему классу, пример выше. | |
10
- 30.06.2014 - 00:00
| NTFS_,достойное решение, более чем :-) Вопрос очень интересный..А как думает уважаемое сообщество, с точки зрения ООП - это норма, зачит, в конструкторе предка инициализировать или нет базовые свойства, в зависимости от того, кого рожаем? Не сочтите за вброс, интересно мнение :-) | |
11
- 07.12.2015 - 18:35
| ДОБАВЬ ПАРАМЕТР В КОНСТРУКТОР ..(..,bool bNeedCall=true) и иф части которой не надо вызывать. А вообще я конструкторами пользуюсь исключительно в отладочных целях, и иню-инициирую явно функциями с приставкой Born..(..) | |
12
- 27.01.2016 - 20:52
| Можно просто в потомке сделать переинициализацию, и все дела.с точки зрения ООП - за это надо на костре сжигать) | |
13
- 30.01.2016 - 23:31
| 11-uxoos > Комитет по стандарту С++ не мог не знать о таком умнейшем программисте, бгг. :) | |
| Интернет-форум Краснодарского края и Краснодара |