2014-05-13 1 views
5

출력은클래스 참조를 사용한 다형성 및 상속? 아래의 콘솔 응용 프로그램의

Parent 
Parent 
Parent 

대신

Parent 
Child1 
Child2 

왜 이런 일이 것입니까? 또한, 의도 된 출력을 얻는 방법? 많은 감사합니다!

PS : 아직 단서가이 related SO post ...

program Project1; 

{$APPTYPE CONSOLE} 

type 
    TParent = class; 
    TParentClass = class of TParent; 

    TParent = class 
    public 
    ID: string; 
    constructor Create; 
    end; 

    TChild1 = class(TParent) 
    public 
    constructor Create; 
    end; 

    TChild2 = class(TParent) 
    public 
    constructor Create; 
    end; 

constructor TParent.Create; 
begin 
    ID := 'Parent'; 
end; 

constructor TChild1.Create; 
begin 
    ID := 'Child1'; 
end;  

constructor TChild2.Create; 
begin 
    ID := 'Child2'; 
end; 

procedure Test(ImplClass: TParentClass); 
var 
    ImplInstance: TParent; 
begin 
    ImplInstance := ImplClass.Create; 
    WriteLn(ImplInstance.ID); 
    ImplInstance.Free; 
end; 

begin 
    Test(TParent); 
    Test(TChild1); 
    Test(TChild2); 
    Readln; 
end. 
+1

참고 코드를 편집했습니다. 'TParent'에서 선언 한 것을 숨기는 파생 된 각 클래스에 새로운'ID' 필드를 추가하는 것을 의미하지 않았습니다. –

답변

9

코드를 읽은 후 당신의 생성자가 가상하지 않기 때문에 그것을 수행하는 방식으로 동작합니다. 즉, 컴파일러가 컴파일 할 때 컴파일러와 바인딩됩니다. 따라서 런타임 유형을 고려할 수없고 코드는 항상 TParent.Create을 호출한다는 의미입니다.

런타임 유형을 사용하여 프로그램을 바인드하려면 가상 메소드와 다형성을 사용해야합니다. 그래서 당신은 가상 생성자를 사용하여 문제를 해결할 수 있습니다 :

program Project1; 

{$APPTYPE CONSOLE} 

type 
    TParent = class; 
    TParentClass = class of TParent; 

    TParent = class 
    public 
    ID: string; 
    constructor Create; virtual; 
    end; 

    TChild1 = class(TParent) 
    public 
    constructor Create; override; 
    end; 

    TChild2 = class(TParent) 
    public 
    constructor Create; override; 
    end; 

constructor TParent.Create; 
begin 
    ID := 'Parent'; 
end; 

constructor TChild1.Create; 
begin 
    ID := 'Child1'; 
end; 

constructor TChild2.Create; 
begin 
    ID := 'Child2'; 
end; 

procedure Test(ImplClass: TParentClass); 
var 
    ImplInstance: TParent; 
begin 
    ImplInstance := ImplClass.Create; 
    WriteLn(ImplInstance.ID); 
    ImplInstance.Free; 
end; 

begin 
    Test(TParent); 
    Test(TChild1); 
    Test(TChild2); 
    Readln; 
end. 

출력

 
Parent 
Child1 
Child2 

여기 엄지 손가락의 규칙입니다 당신이 객체를 인스턴스화 메타 클래스를 사용할 때마다, 당신의 클래스 생성자 가상이어야합니다. 이 경험 법칙에는 예외가 있지만 필자는 개인적으로 프로덕션 코드에서이 규칙을 위반하지 않아도됩니다.

+0

신속하고 유용한 답변을 해주셔서 감사합니다. 그 엄지 손가락 규칙에 대해 더 자세히 설명해 주시겠습니까? 생성자는 "명시 적으로"사용되지 않을 때 가상이어야합니다? – SOUser

+0

엄지 손가락의 아주 좋은 규칙! 대단히 감사합니다! – SOUser