📄 ch03.htm
字号:
the central
constructs that drives BCB. This is the heart of delegation programming model. As
I have said several times, BCB is primarily about components, properties, and the
delegation model. Take events away, and you have some other product
altogether. Events
radically change the way C++ programs are written. The key effect of events on C++
seems to me to be the following: "In addition to using inheritance and virtual
methods to change the behavior of an object, BCB allows you to
customize object by
delegating events. In particular, VCL objects often delegate events to the form on
which they reside."</P>
<P>Like all properties, events work with both standard C++ classes and with VCL classes.
<H3><FONT
COLOR="#000077">declspec(delphiclass | delphireturn | pascalimplementation)</FONT></H3>
<P>All the additions to C++ discussed so far are primarily about finding ways to
support the VCL. In particular, the new VCL object model has certain benefits
associated
with it, and so Borland has extended C++ in order to accommodate this new model.
The property and event syntax, however, appears to have at least some other implications
beyond its simple utilitarian capability to support the VCL. I think
you will find
the next three changes are very small potatoes compared to properties and events.
All they really do is make it possible for BCB to use the VCL, and they don't really
have much effect at all on the way we write code.</P>
<P>As you have
no doubt gleaned by this time, VCL classes behave in specific ways.
For instance, a VCL class can only by instantiated on the heap, and you can only
use the <TT>__published</TT> or <TT>__automated</TT> keywords with VCL classes.</P>
<P>The majority of
the time your own classes can inherit this behavior directly,
simply by descending from a VCL class. For instance, here is part of the declaration
for <TT>TControl</TT></P>
<PRE><FONT COLOR="#0066FF">class __declspec(pascalimplementation) TControl :
public Classes::TComponent
{
typedef Classes::TComponent inherited;
private:
TWinControl* FParent;
... // etc
}
</FONT></PRE>
<P>As you can see, these classes are declared with the <TT>delphiclass</TT> or <TT>pascalimplementation</TT>
attribute. This means they are implemented in Pascal, and the headers are the only
part that appear in C++ code. If you have an Object Pascal unit that you want to
use in a BCB application, the other declarations in the unit will automatically be
translated and placed in a C++ header file. The class declarations in that header
file will be similar to the one shown here.</P>
<P>However, if you create a descendant of <TT>TControl</TT>, you don't have to bother
with any of this, because the
attributes will be inherited:</P>
<PRE><FONT COLOR="#0066FF">class MyControl : public TControl
{
// My stuff here
}
</FONT></PRE>
<P>Class <TT>MyControl</TT> is automatically a VCL class that can support __<TT>published</TT>
properties and must
be created on the heap. It inherits this capability from <TT>TControl</TT>.
As a result, it is implicitly declared <TT>pascalimpementation</TT>, even though
you don't explicitly use the syntax. I don't like to clutter up class declarations
with
<TT>__declspec(pascalimplementation)</TT>, but it may appeal to some programmers
because it makes it clear that the class is a VCL class and has to be treated in
a particular manner.</P>
<P>If you want to create a forward declaration for a class with
the <TT>pascalimplementation</TT>
attribute, it must have the <TT>delphiclass</TT> attribute:</P>
<PRE><FONT COLOR="#0066FF">class __declspec(delphiclass) TControl;
</FONT></PRE>
<P>This is a forward declaration for the <TT>TControl</TT> class found
in <TT>CONTROLS.HPP</TT>.
You do not inherit <TT>delphiclass</TT> in the same sense that you do <TT>pascalimplementation</TT>,
and so you must use it explicitly in forward declarations!</P>
<P><TT>delphireturn</TT> is used to tell the compiler to
generate a particular kind
of code compatible with the VCL when it returns objects or structures from a function.
The only place in BCB where this is done is in <TT>SYSDEFS.H</TT> and <TT>DSTRINGS.H</TT>,
which is where classes like <TT>Currency</TT>,
<TT>AnsiString</TT>, and <TT>Variant</TT>
are declared. If you need to return objects or structures to the VCL, you may need
to declare your class with this directive. However, there are very few occasions
when this is necessary, and most programmers
can forget about <TT>delphireturn</TT>
altogether.
<BLOCKQUOTE>
<P>
<HR>
<FONT COLOR="#000077"><B>NOTE: </B></FONT>As shown later in this chapter, the <TT>TDateTime</TT>
object is declared <TT>delphireturn</TT>. This is necessary because instances
of
the object can be passed to VCL functions such as <TT>DateTimeToString</TT>.
<HR>
</BLOCKQUOTE>
<P>All of this business about <TT>dephireturn</TT> and <TT>pascalimplementation</TT>
has little or no effect on the code written by most BCB
programmers. <TT>delphiclass</TT>
is slightly more important, because you will likely have occasion to declare a forward
declaration for one of your own descendants of a VCL class. This is clearly a case
where you can indeed afford to "pay no
attention to the man behind the curtain."
Most of this stuff is just hand signals passed back and forth between the compiler
and VCL, and you can afford to ignore it. Its impact on the C++ programming as a
whole is essentially nil.
<H3><FONT
COLOR="#000077">classid(class)</FONT></H3>
<P>Use <TT>classid</TT> if you need to pass the specific type of a class to a function
or method used by the VCL RTTI routines. For instance, if you want to call the <TT>ClassInfo</TT>
method of
<TT>TObject</TT>, you need to pass in the type of the class you want to
learn about. In Object Pascal you write</P>
<PRE><FONT COLOR="#0066FF">ClassInfo(TForm);
</FONT></PRE>
<P>which means: Tell me about the <TT>TForm</TT> class. Unfortunately, the
compiler
won't accept this syntax. The correct way to pose the question in BCB is</P>
<PRE><FONT COLOR="#0066FF">ClassInfo(__classid(TForm));
</FONT></PRE>
<P>Again, this is just the compiler and the VCL having a quiet little chat. Pay no
attention
to the man behind the curtain. RTTI looks one way in the VCL, another in
standard C++. This syntax is used to bridge the gap between the two, and it has no
far reaching implications for C++, the VCL, or anyone else. The excitement is all
centered
around the property and event syntax; this is a mere trifle.
<H2><FONT COLOR="#000077">__fastcall</FONT></H2>
<P>The default calling convention in Object Pascal is called <TT>fastcall</TT>, and
it is duplicated in C++Builder with the
<TT>__fastcall</TT> keyword. <TT>__fastcall</TT>
methods or functions usually have their parameters passed in registers, rather than
on the stack. For instance, the value of one parameter might be inserted in a register
such as <TT>EAX</TT> and then
snagged from that register on the other side.</P>
<P>The <TT>__fastcall</TT> calling conventions pass the first three parameters in
<TT>eax</TT>, <TT>edx</TT>, and <TT>ecx</TT> registers, respectively. Additional
parameters and parameter data larger
than 32 bits (such as doubles passed by value)
are pushed on the stack.
<H2><FONT COLOR="#000077">Delphi-Specific Classes</FONT></H2>
<P>Not all the features of C++ are available in Object Pascal, and not all the features
of Object Pascal are
available in BCB. As a result, the following classes are created
to represent features of the Object Pascal language that are not present in C++:</P>
<PRE><FONT COLOR="#0066FF">AnsiString
Variant
ShortString
Currency
TDateTime
Set
</FONT></PRE>
<P>Most of these classes are implemented or declared in <TT>SYSDEFS.H</TT>, though
the crucial <TT>AnsiString</TT> class is declared in its own file called <TT>DSTRINGS.H</TT>.
<BLOCKQUOTE>
<P>
<HR>
<FONT COLOR="#000077"><B>NOTE: </B></FONT>Neither
the <TT>real</TT> nor <TT>comp</TT>
types used in Object Pascal are supported adequately in BCB. Because Pascal programmers
often used the <TT>comp</TT> type to handle currency, they should pay special attention
to the section in this chapter on
the BCB currency type. The real type is an artifact
of the old segmented architecture days when anything and everything was being done
to save space and clock cycles. It no longer plays a role in contemporary Object
Pascal programming.
<HR>
</BLOCKQUOTE>
<P>I will dedicate at least one section of this chapter to each of the types listed
previously. Some important types, such as <TT>Sets</TT> and <TT>AnsiStrings</TT>,
will receive rather lengthy treatment stretching over several
sections.</P>
<P>Many C++ programmers will have questions about the presence of some of these classes.
For instance, C++ comes equipped with a great set template and an excellent string
class. Why does BCB introduce replacements for these classes? The
answer to the question
is simply that BCB needed a class that mimicked the specific behavior of Object Pascal
sets and Object Pascal strings.</P>
<P>Here are some macros you can use with these classes:</P>
<PRE><FONT COLOR="#0066FF">OPENARRAY
ARRAYOFCONST
EXISTINGARRAY
SLICE
</FONT></PRE>
<P>These macros are also discussed in the upcoming sections.
<H2><FONT COLOR="#000077">Introducing the AnsiString Class</FONT></H2>
<P>The C language is famous for its null-terminated strings. These
strings can be
declared in many ways, but they usually look like one of these three examples:</P>
<PRE><FONT COLOR="#0066FF">char MyString[100]; // declare a string with 100 characters in it.
char *MyString; // A pointer to a string with no
memory allocated for it.
LPSTR MyString; // A "portable" Windows declaration for a pointer to a string
</FONT></PRE>
<P>Declarations like these are such a deep-rooted and long standing part of the C
language that it is somewhat
shocking to note that they are not as common as they
once were. There is, of course, nothing wrong with these strings, but C++ has come
up with a new, and perhaps better, way to deal with strings. (I speak of these strings
as being exclusive to C,
though of course these same type of strings are also used
in Object Pascal, where they are called <TT>PChars</TT>.)</P>
<P>The "old-fashioned" types of strings shown previously cause people problems
because it is easy to make memory
allocation errors with them or to accidentally
omit the crucial terminating zero (<TT>`/0'</TT>) that marks the end of these strings.</P>
<P>These same strings are also famous for their accompanying string library, which
includes a series of cryptic
looking functions with names like <TT>strcpy</TT>, <TT>strlen</TT>,
<TT>strcmp</TT>, <TT>strpbrk</TT>, <TT>strrchr</TT>, and so on. These functions,
most of which occur in both C++ and Object Pascal, can be awkward to use at times,
and can frequently
lead to errors if a programmer gets careless.</P>
<P>In this book, I will try to avoid using any of the "old fashioned" C
style strings whenever possible. Instead, I will do things the C++ way and use string
classes. Most C++ programmers
prefer string classes on the grounds that they are
easier to use, easier to read, and much less likely to lead to an error involving
memory allocation.</P>
<P>In this book there is a fourth reason for using string classes. In particular,
a string
class called <TT>AnsiString</TT> provides compatibility with the underlying
strings found in the VCL. C++ programmers will find that <TT>AnsiString</TT>s are
similar to the standard ANSI C++ <TT>String</TT> class.</P>
<P><TT>AnsiString</TT>s are very
easy to use. In fact, many programmers will find
that they have an intuitive logic to them that almost eliminates the need for any
kind of in-depth explanation. However, <TT>AnsiString</TT>s happen to form one of
the key building blocks on which a
great deal of C++Builder code is based. It is
therefore of paramount importance that users of BCB understand <TT>AnsiString</TT>s.</P>
<P>The next few sections of the book take on the task of explaining <TT>AnsiString</TT>s.
To help illustrate this
explanation with ready-made examples, you can turn to the
UsingAnsiString program found on the book's CD-ROM. This program provides examples
of essential <TT>AnsiString</TT> syntax and shows several tricks you can use when
you add strings to your
programs.
<H3><FONT COLOR="#000077">Working with the AnsiString Class</FONT></H3>
<P>The <TT>AnsiString</TT> class is declared in the <TT>DSTRING.H</TT> unit from
the <TT>..\INCLUDE\VCL</TT> directory. This is a key piece of code, and one which
all
BCB programmers should take at least a few minutes to study.</P>
<P>The declaration for the class in the <TT>DSTRING.H</TT> unit is broken up into
several discreet sections. This technique makes the code easy to read. For instance,
one of the sections
shows the operators used for assignments:</P>
<PRE><FONT COLOR="#0066FF">// Assignments
AnsiString& __fastcall operator =(const AnsiString& rhs);
AnsiString& __fastcall operator +=(const AnsiString& rhs);
</FONT></PRE>
<P>Another section shows some comparison operators:</P>
<PRE><FONT COLOR="#0066FF">//Comparisons
bool __fastcall operator ==(const AnsiString& rhs) const;
bool __fastcall operator !=(const AnsiString& rhs) const;
bool __fastcall
operator <(const AnsiString& rhs) const;
bool __fastcall operator >(const AnsiString& rhs) const;
bool __fastcall operator <=(const AnsiString& rhs) const;
bool __fastcall operator >=(const AnsiString& rhs)
const;
</FONT></PRE>
<P>Another handles the <TT>Unicode</TT>-related chores:</P>
<PRE><FONT COLOR="#0066FF">//Convert to Unicode
int __fastcall WideCharBufSize() const;
wchar_t* __fastcall WideChar(wchar_t* dest, int destSize) const;
</FONT></PRE>
<P>There is, of course, much more to the declaration than what I show here. However,
these code fragments should give you some sense of what you will find in <TT>DSTRING.H</TT>,
and of how to start browsing through the code to find
<TT>AnsiString</TT> methods
or operators that you want to use.</P>
<P>The rest of the text in this section of the chapter examines most of the key parts
of the <TT>AnsiString</TT> class and shows how to use them. However, you should definitely
find
time, either now or later, to open up <TT>DSTRING.H</TT> and to browse through
its contents.
<H3><FONT COLOR="#000077">AnsiString Class Constructors</FONT></H3>
<P><TT>AnsiString</TT>s are a class; they are not a simple type like the string type
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -