2009-08-06 6 views
2

Si j'écrisTypes de classe et Constructor Appels

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

le constructeur correct (celui dans TMyClass) est appelée.

Si j'écris

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

que le constructeur TObject est appelé.

Pourquoi? Quelle est la différence entre les deux versions? Puis-je forcer l'appel du constructeur TMyClass dans le second scénario?

Répondre

11

TClass est déclaré "Class of TObject" dans system.pas. Quel constructeur est appelé est décidé à la compilation, et tout le compilateur sait quelle classe de base vous utilisez. Il ne sait pas quelle sera la valeur de la variable quand elle s'exécutera, elle doit donc être définie par défaut sur la classe de base. Si vous utilisez un TClass, votre classe de base est TObject.

Si vous utilisez une variable de classe, je suppose que vous avez une sorte de hiérarchie et que vous essayez d'implémenter une fabrique. Si vous voulez vous assurer que le bon constructeur est appelé en fonction de la valeur d'une variable de classe au moment de l'exécution, pas quelque chose contenu dans votre code au moment de la compilation, vous avez besoin d'un constructeur virtuel.

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

    TMyClass = class of TMyBaseObject; 

Utilisez un TMyClass au lieu d'un TClass comme variable de classe, et maintenant le compilateur génère un appel à TMyBaseObject.Create, qui est virtuel. Assurez-vous que toutes vos classes dérivées remplacent le constructeur de base, et vous finirez par appeler le bon à l'exécution.

+0

+1 merci! Y a-t-il quelque chose de négatif sur le fait que le constructeur soit virtuel? Plus précisément, existe-t-il une raison pour laquelle TObject.Create n'est pas virtuel? – jpfollenius

+1

Probablement parce qu'il n'est pas nécessaire que ce soit virtuel. Tout d'abord, les appels de méthode virtuelle ne fonctionnent qu'avec des signatures identiques, et la plupart des constructeurs prennent au moins un paramètre. Deuxièmement, si vous utilisez le modèle d'usine de cette façon, vous voulez probablement un descendant d'une classe spécifique de toute façon. –

2

Je suggérerais que vous envisagiez de surcharger la méthode AfterConstruction qui est introduite par le TObject pour faire du polymorphisme comme ce travail.

Chaque définition de classe peut introduire un nouveau constructeur, avec son propre ensemble de paramètres. Une variable de classe connaît seulement le constructeur si la classe de base est une variable pour. Tout cela est possible car un constructeur n'est ni virtuel ni surchargé. Vous pouvez marquer le constructeur virtual sur votre classe de base et marquer toutes les classes décroissantes, ce qui bloque la liste des paramètres. (Je pense que si vous oubliez 'override', le compilateur avertit que votre nouveau constructeur cache le virtual.)

+0

Cela ne résoudra pas le problème de base. Sans constructeur virtuel, il finira toujours par créer des objets TObject au lieu de la classe qu'il cherche. –

+0

Avez-vous essayé? étant donné le code dans la question et TSomeOtherObject = class (TMyBaseObject), si vous définissez Someclass: TMyClass à TSomeOtherObject, il doit contenir le pointeur en mémoire sur les données de classe, y compris le constructeur surchargé. (Je pense, devrait essayer moi-même ...) –

+0

Oh, bien oui, s'il utilise une variable de classe plus spécifique. Je pensais que vous vouliez dire qu'il pourrait utiliser un TClass et un override AfterConstruction pour obtenir le bon comportement sur tout ce qui descend de TObject. –

4

TObject.Create n'est pas virtuel, vous devez déclarer ClassVar comme un classtype d'une classe avec un constructeur virtuel.

-3

Ou descendez-le de TComponent, qui possède déjà un constructeur virtuel.

+0

-1 ... Plus de frais généraux dont je n'ai pas vraiment besoin. Et c'est confus: "Les composants sont des objets persistants qui ont les capacités suivantes: intégration IDE, propriété, streaming et archivage, support COM" (cité dans Delphi Help) ... ce n'est pas vraiment ce que je veux ici. – jpfollenius

+0

N'a jamais eu des problèmes de vitesse avec TComponent. Et pour le support COM, je sais qu'il fait ref couting si le descendant est un wrapper pour un objet COM (champ VCLComObject). Et la propriété est une bénédiction quand il est nécessaire de créer des sous-objets qui doivent être détruits lors de la simulation. Intégrations IDE signifie simplement que vous pouvez l'enregistrer sur une palette. Donc, j'utilise TComponent comme base pour mes objets, oui. –

+0

Une classe ne doit descendre de TComponent que s'il s'agit d'un composant. –

Questions connexes