![]() |
С++/C#/Java - как не вызывать конструктор предка в потомке Всем добрый день. Столкнулся с необходимость перенести несложный код с 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 - тогда я решу проблему другим способом. Если же есть вариант, пусть даже технически извращенный - буду очень благодарен за подсказку. |
А что мешает 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"); ** ** ** ------------- |
Спасибо, думал об этом, но это не совсем то. public CBase() ** if (!(this is Cbase2)) ** Получается, что базовый класс должен знать что-то о потомке - это еще хуже для логики. А если потомков штук 10? То, что исходная задача скорее всего возникла из-за кривой архитектуры классов - очевидно, но всё-таки, Pascal мне эту возможность прострелить ногу предоставляет. А С++, походу, нет. |
Именно "прострелить ногу". В паскале легко "забыть" про необходимость вызова базового конструктора в конструкторе потомка. И получить неполноценно инициализированный объект просто из-за забывчивости. А в сях, чтобы получить "неполноценный" объект, нужно специально писать соответсвующий код в базовом классе. Т.е. ты на 100% знаешь что делаешь. ИМХО так... |
Паскаль дает пистолет и говорит - делай что хочешь, попадешь в ногу - сам виноват. С дает пистолет, но при этом, чтобы выстрелить в ногу, нужно на этом пистолете осознано переключить большой красный переключатель в режим "выстрел в ногу". |
Угм, примерно так и думал. Значит, просто перепишу логику и не буду мучить С++ с Явой странными хотелками. PS: Паскаль обычно наследует конструктор по умолчанию. В общем случае, это ещё лучше и проще, чем обязательное прописывание в С++ TBase2(int Ax) : TBase(Ax) **** ; |
В общем случае если нужно в потомке сделать особую инициализацию, то в java используется метод, который вызывается в конструкторе родителя, и по необходимости определяется в потомке, но это плохое решение. лучшее надо смотреть от задачи. |
0-NTFS_ > Какое-то хреновое ООП =) Проверка в родительском конструкторе на вызов для создания объекта другого класса не подойдет? if (!this.getClass().equals(Parent.class)) ? |
7-40KHYTbIU > [I]Проверка в родительском конструкторе на вызов для создания объекта другого класса не подойдет? [/I] Подойдет, конечно, но это означает, что родитель должен знать что-то о своих потомках. Проблему решил, просто выкинул весь код с хитрым наследованием и поставил фабрику. Это заняло 10 минут кодирования и 20 минут объяснений заказчику, что это за странное колдовство с вводом нового класса :-) |
[quote=NTFS_;35639519]Подойдет, конечно, но это означает, что родитель должен знать что-то о своих потомках. [/quote] Конструктор родителя может проверить класс вызвавшего объекта на равенство своему классу, пример выше. |
NTFS_,достойное решение, более чем :-) Вопрос очень интересный..А как думает уважаемое сообщество, с точки зрения ООП - это норма, зачит, в конструкторе предка инициализировать или нет базовые свойства, в зависимости от того, кого рожаем? Не сочтите за вброс, интересно мнение :-) |
ДОБАВЬ ПАРАМЕТР В КОНСТРУКТОР ..(..,bool bNeedCall=true) и иф части которой не надо вызывать. А вообще я конструкторами пользуюсь исключительно в отладочных целях, и иню-инициирую явно функциями с приставкой Born..(..) |
[quote=NTFS_;35559154]Если условие, то вызываем конструктор, иначе - особая инициализация[/quote]Можно просто в потомке сделать переинициализацию, и все дела.[quote=Гость;35706365]с точки зрения ООП - это норма, зачит, в конструкторе предка инициализировать или нет базовые свойства, в зависимости от того, кого рожаем? [/quote]с точки зрения ООП - за это надо на костре сжигать) |
11-uxoos > Комитет по стандарту С++ не мог не знать о таком умнейшем программисте, бгг. :) |
Текущее время: 23:53. Часовой пояс GMT +3. |