2009-08-06 5 views
2

클래스 유형 및 생성자 호출

type 
    MyClass = class of TMyClass; 
... 
Obj := MyClass.Create; 

을 작성하면 올바른 생성자 (TMyClass에있는 생성자)가 호출됩니다.

var 
    ClassVar : TClass; 
... 
ClassVar := TMyClass; 
Obj := ClassVar.Create; 

을 쓰면 TObject 생성자 만 호출됩니다.

이유가 무엇입니까? 두 버전의 차이점은 무엇입니까? 두 번째 시나리오에서 TMyClass 생성자 호출을 강제로 수행 할 수 있습니까?

답변

11

TClass는 system.pas에서 "Class of TObject"으로 선언되었습니다. 어떤 생성자가 호출되는지는 컴파일 타임에 결정되며, 모든 컴파일러는 여러분이 사용하고있는 기본 클래스를 알고 있습니다. 변수가 실행될 때 변수의 값이 무엇인지 알지 못하므로 기본 클래스를 기본값으로 사용해야합니다. TClass를 사용하는 경우 기본 클래스는 TObject입니다.

클래스 변수를 사용하는 경우 일종의 계층 구조가 있다고 가정하고 팩토리를 구현하려고합니다. 컴파일 타임에 코드에 포함 된 것이 아닌 런타임에 클래스 변수의 값을 기반으로 올바른 생성자가 호출되도록하려면 가상 생성자가 필요합니다.

type 
    TMyBaseObject = class(TObject) 
    public 
    constructor Create; virtual; 
    end; 

    TMyClass = class of TMyBaseObject; 

는 클래스 변수로 인 TClass 대신 타입을 TMyClass를 사용하여, 지금 컴파일러는 가상이다 TMyBaseObject.Create에 대한 호출을 생성합니다. 모든 파생 클래스가 기본 생성자를 재정의했는지 확인하면 런타임에 올바른 호출을 종료하게됩니다.

+0

+1 감사합니다. 가상 생성자에 대해 나쁜 점이 있습니까? 특히 TObject.Create가 가상이 아닌 이유가 무엇입니까? – jpfollenius

+1

아마도 가상 일 필요가 없기 때문일 것입니다. 첫째, 가상 메서드 호출은 동일한 서명으로 만 작동하며 대부분의 생성자는 적어도 하나의 매개 변수를 사용합니다. 둘째, 이런 식으로 팩토리 패턴을 사용한다면 어쨌든 특정 클래스의 자손을 원할 것입니다. –

2

이 작업과 같은 다형성을 만들기 위해 TObject에서 소개 한 AfterConstruction 메서드를 재정의하는 것이 좋습니다.

각 클래스 정의는 고유 한 매개 변수 집합을 사용하여 새 생성자를 도입 할 수 있습니다. 클래스 변수는 그것이 기본 클래스 인 경우 생성자 만 알고 있습니다. 이것은 생성자가 가상도 오버라이드도되지 않기 때문에 가능한 모든 것입니다. 기본 클래스에서 생성자 virtual에 플래그를 지정하고 매개 변수 목록을 차단하는 모든 내림차순 클래스 재정의 플래그를 지정할 수 있습니다. (당신이 'override'를 잊어 버리면 컴파일러가 새로운 생성자가 가상 ​​객체를 숨 깁니다.)

+0

기본 문제는 해결되지 않습니다. 가상 생성자가 없으면 그는 찾고자하는 클래스 대신 항상 TObject 객체를 생성하게됩니다. –

+0

시도해 보셨습니까? 질문에 코드가 있고 TSomeOtherObject = class (TMyBaseObject) 인 경우 Someclass : TMyClass를 TSomeOtherObject로 설정하면 재정의 된 생성자를 포함하여 클래스 데이터에 대한 메모리 내 포인터를 보유해야합니다. (내 생각에, 직접 해봐야한다고 생각합니다 ...) –

+0

오, 그래, 그가 더 구체적인 클래스 변수를 사용한다면. 내가 Tclass와 AfterConstruction 오버라이드를 사용하여 TObject에서 내림차순으로 올바른 동작을 얻을 수 있다는 것을 의미한다고 생각했습니다. –

4

TObject.Create가 가상이 아니므로 ClassVar을 가상 생성자가있는 클래스의 클래스 유형으로 선언해야합니다.

-3

또는 이미 가상 생성자가있는 TComponent에서 강하합니다.

+0

-1 ... 정말 필요하지 않은 오버 헤드가 많습니다. 그리고 그것은 혼란 스럽습니다 : "컴포넌트는 IDE 통합, 소유권, 스트리밍 및 파일링, COM 지원"(델파이 도움말에서 인용 한)과 같은 영구 객체입니다 ... 여기서 내가 원하는 것은 아닙니다. – jpfollenius

+0

TComponent에 속도 문제가 없었습니다. 그리고 COM 지원을 위해, 나는 그것이 후손이 COM 객체 (VCLComObject 필드)에 대한 래퍼 (wrapper)인지 아닌지를 알아 낸다. 그리고 comp 소유가 파괴 될 때 파괴되어야하는 subobjects를 생성 할 필요가있을 때 소유권은 축복입니다. IDE 통합은 팔레트에 등록 할 수 있다는 것을 의미합니다. 따라서 TComponent를 내 객체의 기반으로 사용합니다. –

+0

클래스는 구성 요소 인 경우에만 TComponent에서 파생되어야합니다. –