Форум на Kuban.ru (http://forums.kuban.ru/)
-   Разработка программ (http://forums.kuban.ru/f1024/)
-   -   С++/C#/Java - как не вызывать конструктор предка в потомке (http://forums.kuban.ru/f1024/s_c_java_-_kak_ne_vyzyvat-_konstruktor_predka_v_potomke-5810227.html)

NTFS_ 16.06.2014 13:05

С++/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 - тогда я решу проблему другим способом.

Если же есть вариант, пусть даже технически извращенный - буду очень благодарен за подсказку.

spaceman 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");
**


**
**
-------------

NTFS_ 16.06.2014 16:13

Спасибо, думал об этом, но это не совсем то.

public CBase()
**
if (!(this is Cbase2))
**

Получается, что базовый класс должен знать что-то о потомке - это еще хуже для логики. А если потомков штук 10?

То, что исходная задача скорее всего возникла из-за кривой архитектуры классов - очевидно, но всё-таки, Pascal мне эту возможность прострелить ногу предоставляет. А С++, походу, нет.

spaceman 16.06.2014 16:22

Именно "прострелить ногу". В паскале легко "забыть" про необходимость вызова базового конструктора в конструкторе потомка. И получить неполноценно инициализированный объект просто из-за забывчивости. А в сях, чтобы получить "неполноценный" объект, нужно специально писать соответсвующий код в базовом классе. Т.е. ты на 100% знаешь что делаешь.
ИМХО так...

spaceman 16.06.2014 16:27

Паскаль дает пистолет и говорит - делай что хочешь, попадешь в ногу - сам виноват.
С дает пистолет, но при этом, чтобы выстрелить в ногу, нужно на этом пистолете осознано переключить большой красный переключатель в режим "выстрел в ногу".

NTFS_ 16.06.2014 16:50

Угм, примерно так и думал. Значит, просто перепишу логику и не буду мучить С++ с Явой странными хотелками.

PS: Паскаль обычно наследует конструктор по умолчанию. В общем случае, это ещё лучше и проще, чем обязательное прописывание в С++
TBase2(int Ax) : TBase(Ax) **** ;

wayerr 16.06.2014 21:44

В общем случае если нужно в потомке сделать особую инициализацию, то в java используется метод, который вызывается в конструкторе родителя, и по необходимости определяется в потомке, но это плохое решение.

лучшее надо смотреть от задачи.

40KHYTbIU 23.06.2014 09:27

0-NTFS_ > Какое-то хреновое ООП =)
Проверка в родительском конструкторе на вызов для создания объекта другого класса не подойдет?

if (!this.getClass().equals(Parent.class)) ?

NTFS_ 23.06.2014 11:31

7-40KHYTbIU >
[I]Проверка в родительском конструкторе на вызов для создания объекта другого класса не подойдет?
[/I]

Подойдет, конечно, но это означает, что родитель должен знать что-то о своих потомках.
Проблему решил, просто выкинул весь код с хитрым наследованием и поставил фабрику. Это заняло 10 минут кодирования и 20 минут объяснений заказчику, что это за странное колдовство с вводом нового класса :-)

40KHYTbIU 24.06.2014 00:17

[quote=NTFS_;35639519]Подойдет, конечно, но это означает, что родитель должен знать что-то о своих потомках. [/quote]
Конструктор родителя может проверить класс вызвавшего объекта на равенство своему классу, пример выше.

AlienX 30.06.2014 00:00

NTFS_,достойное решение, более чем :-) Вопрос очень интересный..А как думает уважаемое сообщество, с точки зрения ООП - это норма, зачит, в конструкторе предка инициализировать или нет базовые свойства, в зависимости от того, кого рожаем? Не сочтите за вброс, интересно мнение :-)

uxoos 07.12.2015 18:35

ДОБАВЬ ПАРАМЕТР В КОНСТРУКТОР ..(..,bool bNeedCall=true) и иф части которой не надо вызывать. А вообще я конструкторами пользуюсь исключительно в отладочных целях, и иню-инициирую явно функциями с приставкой Born..(..)

hondroxid 27.01.2016 20:52

[quote=NTFS_;35559154]Если условие, то вызываем конструктор, иначе - особая инициализация[/quote]Можно просто в потомке сделать переинициализацию, и все дела.[quote=Гость;35706365]с точки зрения ООП - это норма, зачит, в конструкторе предка инициализировать или нет базовые свойства, в зависимости от того, кого рожаем? [/quote]с точки зрения ООП - за это надо на костре сжигать)

maksss 30.01.2016 23:31

11-uxoos > Комитет по стандарту С++ не мог не знать о таком умнейшем программисте, бгг. :)


Текущее время: 22:33. Часовой пояс GMT +3.