📄 ch19.htm
字号:
private:
virtual TObject* __fastcall NewInstance(TClass cls);
public:
virtual void __fastcall FreeInstance();
virtual __fastcall ~TObject() {}
};
</FONT></PRE>
<P>You can find the entire
implementation of <TT>TObject</TT> in the Object Pascal
<TT>System.pas</TT> unit that ships with BCB. Much of it is actually in assembler,
but the source is there if you want to study it. You should, of course, also examine
the declaration for
<TT>TObject</TT> in <TT>SysDefs.h</TT>. The calls in <TT>SysDefs.h</TT>,
however, ultimately resolve into calls to the Pascal implementation in <TT>System.pas</TT>.
I should perhaps add that the <TT>TObject</TT> declaration in <TT>SysDefs.h</TT>
is
very hard to understand, but I promise you that it does end up resolving into
calls that access the <TT>System.pas</TT> version of <TT>TObject</TT>.
<DL>
<DT></DT>
</DL>
<BLOCKQUOTE>
<P>
<HR>
<FONT COLOR="#000077"><B>NOTE:</B></FONT><B>
</B>Although I have mentioned this subject
before, it's probably once again time to stress the importance of viewing the Pascal
source code to the VCL. Your version of BCB might or might not ship with the source,
but if you don't have it and can
possibly afford to buy it, you should think seriously
about obtaining it. You should peruse the <TT>BCB\Include\VCL</TT> subdirectory that
contains the header files for the imported VCL Pascal units. These files provide
the interface for key BCB
units. They are not as good as having the source, but they
are very valuable. I refer to both the header files and the Pascal source continuously.
<HR>
</BLOCKQUOTE>
<P>You can see that <TT>TObject</TT> has a few basic functions declared right
at
the top:</P>
<PRE><FONT COLOR="#0066FF">__fastcall TObject() {}
__fastcall Free();
virtual __fastcall ~TObject() {}
</FONT></PRE>
<P>The point to grasp here is that <TT>TMyObject</TT> has a destructor and <TT>Free</TT>
method because it inherits
them from <TT>TObject</TT>.</P>
<P>To understand this point, you can add a line of code to the nascent OBJECT1 program:</P>
<PRE><FONT COLOR="#0066FF">#include <conio.h>
#include <stdio.h>
int main(void)
{
TMyObject *MyObject = new
TMyObject;
AnsiString S = MyObject->ClassName();
printf(S.c_str());
delete MyObject;
getch();
return 0;
}
</FONT></PRE>
<P>This code enables the object to write its name to the screen. The output from
this program is a single
string:</P>
<PRE><FONT COLOR="#0066FF">TMyObject
</FONT></PRE>
<P>When you run the program, this string might flash by too quickly for leisurely
perusal. To remedy the situation, add a <TT>getch()</TT> at the very end of the code,
right before
the<TT> return</TT> statement. To end this program, press Enter. (That's
the way it used to be done back in the DOS world.)</P>
<P>If you want to, you can even get this object to say its parent's name:</P>
<PRE><FONT COLOR="#0066FF">int main(void)
{
TMyObject *MyObject = new TMyObject;
printf(Format("ClassName: %s\nParent's ClassName: %s",
OPENARRAY(TVarRec, (
MyObject->ClassName(),
MyObject->ClassParent()->ClassName()))).c_str());
delete MyObject;
getch();
return 0;
}
</FONT></PRE>
<P>The output from this code is the following:</P>
<PRE><FONT COLOR="#0066FF">ClassName: TMyObject
Parent's ClassName: TObject
</FONT></PRE>
<P>The point, of course, is that <TT>TMyObject</TT> inherits quite a
bit of functionality
from its parent, and, as a result, it has numerous capabilities that might not be
obvious from merely viewing its declaration.</P>
<P>The ability to trace an object's ancestry is relatively appealing, so it might
be nice to add it
to <TT>TMyObject</TT> as a method:</P>
<PRE><FONT COLOR="#0066FF">#include <vcl/vcl.h>
#include <stdio.h>
#include <conio.h>
#include "classrefs.h"
USEUNIT("ClassRefs.cpp");
class TMyObject : public TObject
{
public:
TMyObject() : TObject() {}
void PrintString(AnsiString S);
void ShowHierarchy();
};
void TMyObject::PrintString(AnsiString S)
{
printf("%s\n", S.c_str());
}
void TMyObject::ShowHierarchy()
{
TClass
AClass;
AnsiString AClassName = AnsiString(ClassName()).c_str();
PrintString(AClassName);
AClass = ClassParent();
while (AClass)
{
AClassName = AnsiString(AClass->ClassName());
PrintString(AClassName);
AClass =
AClass->ClassParent();
}
}
int main(void)
{
ShowClassReferences();
TMyObject *MyObject = new TMyObject;
MyObject->ShowHierarchy();
delete MyObject;
getch();
return 0;
}
</FONT></PRE>
<P>This version of the OBJECT1
program includes two methods, listed in the <TT>TMyObject</TT>
class declaration:</P>
<PRE><FONT COLOR="#0066FF">class TMyObject : public TObject
{
public:
TMyObject() : TObject() {}
void PrintString(AnsiString S);
void ShowHierarchy();
};
</FONT></PRE>
<P>Take a look at the implementation for <TT>ShowHierarchy</TT>. Perhaps the first
thing you notice in it is the class reference in the first line, which uses the <TT>TClass</TT>
type.</P>
<P>The type <TT>TClass</TT> is an object
reference and is declared in <TT>Sysdefs.h</TT>
as follows:</P>
<PRE><FONT COLOR="#0066FF">typedef TMetaClass* TClass;
</FONT></PRE>
<P>Because <TT>ClassParent</TT> returns a variable of type <TT>TClass</TT>, it is
obviously what needs to be used
here.
<DL>
<DT></DT>
</DL>
<BLOCKQUOTE>
<P>
<HR>
<FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>An object reference is a special
metaclass that can be assigned to an object. Here is a unit that shows some legal
uses of an object
reference:</P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////
// ClassRefs.cpp
// Object1
// copyright (c) 1997 by Charlie Calvert
//
#include <vcl\vcl.h>
#include <forms.hpp>
#pragma hdrstop
#include
"ClassRefs.h"
TClass AClass;
class TDescendant: public TObject
{
public:
TDescendant(): TObject() {}
</FONT></PRE>
</BLOCKQUOTE>
<DL>
<DL>
<DT><FONT COLOR="#0066FF"></FONT></DT>
</DL>
</DL>
<BLOCKQUOTE>
<PRE><FONT
COLOR="#0066FF">
};
void ShowClassReferences()
{
printf("** Start object references **\n");
AClass = __classid(TObject);
printf("%s\n", AnsiString(AClass->ClassName()).c_str());
AClass = __classid(TDescendant);
printf("%s\n", AnsiString(AClass->ClassName()).c_str());
AClass = __classid(TForm);
printf("%s\n", AnsiString(AClass->ClassName()).c_str());
printf("** End object references **\n\n");
}</FONT></PRE>
<P>Notice that you do not have to create an object before you can use it with an
<TT>object reference</TT>. In general, you can call any of the static methods of
<TT>TObject</TT> with a class reference. <BR>
<BR>
You cannot use an object reference
to refer to a field that belongs only to the child
of the <TT>object reference</TT> type. For instance, this code does not compile because
<TT>Caption</TT> is not a property of <TT>TObject</TT>:</P>
<PRE><FONT COLOR="#0066FF">ObjectRef =
__classid(TForm)
ObjectRef.Caption := `Sam';
WriteLn(ObjectRef.Caption);</FONT></PRE>
<P>You will find a version of the <TT>CLSREF</TT> unit in the same subdirectory as
OBJECT1. You can use the Project Manager to add this file to the project, and
you
can then call it in the second line of the body of the OBJECT1 program. However,
you should not leave this unit as part of the project, because it will muddy the
view of the object hierarchy that you get in the Browser. <BR>
<BR>
There are
not that many times in which you need to use an object reference in day-to-day
programming. If you are not totally clear on what they do, you can probably afford
to skip the subject. If you really want to know more, you should examine
<TT>Sysdefs.h</TT>;
recognize that the <TT>TMetaClass</TT> you see there is the C++ way of creating a
feature that exists in the VCL. The reason the VCL supports this feature is that
it needs fairly extensive Run Time Type Information (RTTI) in
order to run, and it
gets a good portion of that information from the methods in <TT>TObject</TT> that
are part of <TT>TMetaClass</TT> and are in turn used in an object reference.
<HR>
</BLOCKQUOTE>
<P>When you get past the object reference, the
remaining portions of the <TT>ShowHierarchy</TT>
method are fairly straightforward:</P>
<PRE><FONT COLOR="#0066FF">void TMyObject::ShowHierarchy()
{
TClass AClass;
AnsiString AClassName = AnsiString(ClassName()).c_str();
PrintString(AClassName);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -