⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch03.htm

📁 好书《C++ Builder高级编程技术》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
in 
Object Pascal, which they mimic. Object Pascal or BASIC programmers might find
that the next line of code looks a little like a simple type declaration. It is not.
Instead, this code calls the constructor for an object:</P>
<PRE><FONT 
COLOR="#0066FF">AnsiString S;

</FONT></PRE>
<P>Here are the available constructors for the <TT>AnsiString</TT> class:</P>
<PRE><FONT COLOR="#0066FF">__fastcall AnsiString(): Data(0) {}

__fastcall AnsiString(const char* src);

__fastcall 
AnsiString(const AnsiString&amp; src);

__fastcall AnsiString(const char* src, unsigned char len);

__fastcall AnsiString(const wchar_t* src);

__fastcall AnsiString(char src);

__fastcall AnsiString(int src);

__fastcall AnsiString(double src);


</FONT></PRE>
<P>The simple <TT>AnsiString</TT> declaration shown at the beginning of this section
would call the first constructor shown previously, which initializes to zero a private
variable of the <TT>AnsiString</TT> class. This private variable, 
named <TT>Data</TT>,
is of type <TT>char *</TT>. <TT>Data</TT> is the core C string around which the <TT>AnsiString</TT>
class is built. In other words, the <TT>AnsiString</TT> class is a wrapper around
a simple C string, and the class exists to make 
it easy to manipulate this string
and to make the string compatible with the needs of the VCL.</P>
<P>The following simple declaration would call the second constructor shown in the
previous list:</P>
<PRE><FONT COLOR="#0066FF">AnsiString 
S(&quot;Sam&quot;);

</FONT></PRE>
<P>This is the typical method you would use when initializing a variable of type
<TT>AnsiString</TT>.


<BLOCKQUOTE>
	<P>
<HR>
<FONT COLOR="#000077"><B>NOTE: </B></FONT>I have included a second example program
	
called <TT>UsingAnsiString2</TT>, which features a small class that overrides all
	the constructors for the <TT>AnsiString</TT> class:</P>
	<PRE><FONT COLOR="#0066FF">class MyAnsiString : public AnsiString

{

public:

  __fastcall MyAnsiString(void): 
AnsiString() {}

  __fastcall MyAnsiString(const char* src): AnsiString(src) {}

  __fastcall MyAnsiString(const AnsiString&amp; src): AnsiString(src) {}

  __fastcall MyAnsiString(const char* src, unsigned char len): AnsiString     (src, len) {}

  
__fastcall MyAnsiString(const wchar_t* src): AnsiString(src) {}

  __fastcall MyAnsiString(char src): AnsiString(src) {}

  __fastcall MyAnsiString(int src): AnsiString(src) {}

  __fastcall MyAnsiString(double src): AnsiString(src) {}


};</FONT></PRE>
	<P>This class is provided so you can step through the constructors to see which ones
	are being called. For instance, the three constructors shown immediately after this
	note have been rewritten in the UsingAnsiStrings2 program to 
use <TT>MyAnsiStrings</TT>
	rather than <TT>AnsiString</TT>s. This gives you an easy-to-use system for explicitly
	testing which constructors are being called in which circumstance.<BR>
	<BR>
	When I come up with a unit like this that may be of some 
general utility in multiple
	programs, I usually put it in the <TT>utils</TT> subdirectory located on the same
	level as the chapter subdirectories. In other words, I move or copy it out of the
	directory where the files for the current program are 
stored and place it in a subdirectory
	called <TT>utils</TT> that is on the same level as the directories called <TT>Chap01</TT>,
	<TT>Chap02</TT>, and so on. <BR>
	<BR>
	You might need to add this directory to the include search path for your 
project,
	or the program might not be able to find the <TT>MyAnsiString.h</TT> unit. To set
	up the compiler for your system, go to Options | Project | Directories/Conditionals
	and change the Include Path to point to the directory where 
<TT>MyAnsiString.h</TT>
	is stored.<BR>
	<BR>
	Sometimes I will leave one frozen copy of a unit in the directory where it was first
	introduced and continue development of the copy of the unit that I place in the <TT>utils</TT>
	subdirectory. That 
way, you can find one copy of the file that looks the way you
	expect it to look in the same directory as the program in which I introduce it, while
	continuing to develop the code in a separate unit of the same name found in the <TT>utils</TT>
	
directory. Check the <TT>Readme.txt</TT> file on the CD that accompanies this book
	for further information. 
<HR>


</BLOCKQUOTE>

<P>The following are a few simple examples from the UsingAnsiStrings program that
show examples of creating and using 
<TT>AnsiString</TT>s:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall TForm1::PassinCString1Click(TObject *Sender)

{

  AnsiString S(&quot;Sam&quot;);

  Memo1-&gt;Text = S;

}



void __fastcall TForm1::PassInInteger1Click(TObject *Sender)

{

  
AnsiString MyNum(5);

  Memo1-&gt;Text = MyNum;

}



void __fastcall TForm1::PassInaDouble1Click(TObject *Sender)

{

  AnsiString MyDouble(6.6);

  Memo1-&gt;Text = MyDouble;

}

</FONT></PRE>
<P>This code demonstrates several things. The first, and 
most important point, is
that it shows how you can create an <TT>AnsiString</TT> object by initializing it
with a string, an integer, or a double. In short, these constructors can automatically
perform conversions for you. This means you can usually 
write code like this:</P>
<PRE><FONT COLOR="#0066FF">AnsiString S;

int I = 4;

S = I;

ShowMessage(S);

</FONT></PRE>
<P>When working with C strings, you always have to be careful that the variable you
have been working with has been properly 
initialized. This is not nearly as big a
concern when you are working with <TT>AnsiString</TT>s. Consider the following code:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall TForm1::InitializetoZero1Click(TObject *Sender)

{

  AnsiString S;

  
Memo1-&gt;Text = S.Length();

}

</FONT></PRE>
<P>The first line creates an <TT>AnsiString</TT> class that has a zero length string.
The second line performs a completely safe and legal call to one of the methods of
this <TT>AnsiString</TT>. This is 
the type of situation that can be very dangerous
in C. Here, for instance, is some code that is likely to blow up on you:</P>
<PRE><FONT COLOR="#0066FF">char *S;

int i = strlen(S);

</FONT></PRE>
<P>This code appears to do more or less the same thing 
as the code in the <TT>InitializetoZero1Click</TT>
method. In practice, however, this latter example actually raises an access violation,
while the <TT>AnsiString</TT> code example succeeds. The explanation is simply that
the declaration of the 
<TT>AnsiString</TT> class created a real instance of an object
called <TT>S</TT>. You can safely call the methods of that object, even if the underlying
string has no memory allocated for it! The second example, however, leaves the <TT>char
*</TT> 
declared in the first line completely impotent, with no memory allocated for
it. If you want to avoid trouble, you should not do anything with that variable until
you allocate some memory for it.</P>
<P>In the last few paragraphs I have outlined an 
example illustrating what it is
I like about the <TT>AnsiString</TT> class. In short, this class makes strings safe
and easy to use.


<BLOCKQUOTE>
	<P>
<HR>
<FONT COLOR="#000077"><B>NOTE: </B></FONT>It goes without saying that C strings are
	
generally faster than <TT>AnsiString</TT>s, and that they take up less memory. Clearly,
	these are important features, and obviously I am not stating that C strings are now
	obsolete.<BR>
	<BR>
	The reasoning on this issue is a bit like that we 
undertake when deciding whether
	to buy a car or a motorcycle. Cars are more expensive than motorcycles, and they
	don't let you weave back and forth between lanes when there is congested traffic.
	On the other hand, drivers of cars are much less 
likely to end up in the hospital,
	and cars are much more pleasant to be in during inclement weather. In the same way,
	<TT>AnsiString</TT>s aren't as small and flexible as C strings, but they are less
	likely to crash the system, and they stand up 
better when you are in a rush or when
	handled by inexperienced programmers.<BR>
	<BR>
	This book focuses on ways to quickly write safe, high-performance programs. If that
	is your goal, use <TT>AnsiString</TT>s. If you are trying to write an 
operating system,
	a compiler, or the core module for a 3D game engine, you should probably concentrate
	more on speed than I do in this book and should use <TT>AnsiString</TT>s only sparingly.<BR>
	<BR>
	Please note that my point here is not that you 
can't use C++Builder to write highly
	optimized code, but only that this book usually does not focus on that kind of project.
	
<HR>


</BLOCKQUOTE>

<H3><FONT COLOR="#000077">Sticky Constructor Issues</FONT></H3>
<P>The <TT>AnsiString</TT> 
constructors are easy to use, but things can be a bit
confusing if you try to think about what is going on behind the scenes. For instance,
consider what happens when you pass an <TT>AnsiString</TT> to a function:</P>
<PRE><FONT 
COLOR="#0066FF">AnsiString S;

MyFunc(S);

</FONT></PRE>
<P>If the call to <TT>MyFunc</TT> is by value, not by reference, the constructor
for <TT>S</TT> is going to be called each time you pass the string. This is not a
tremendous burden on your 
program, but it is probably a bit more significant weight
than you had in mind to impose on your code. As a result, you should pass in the
address of the variable in most circumstances:</P>
<PRE><FONT COLOR="#0066FF">AnsiString S;

MyFunc(&amp;S);


</FONT></PRE>
<P>Even better, you should construct methods that declare all their string variables
as being passed by reference:</P>
<PRE><FONT COLOR="#0066FF">int MyFunc(AnsiString &amp;S)

{

  S = &quot;The best minds of my generation...&quot;;

  
return S.Length();

}

</FONT></PRE>
<P>This is like a <TT>var</TT> parameter in Object Pascal in that it lets you pass
the string by reference without worrying about pointers:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall 
TForm1::Button1Click(TObject *Sender)

{

  AnsiString S;

  int i = MyFunc(S);

  ShowMessage(S + &quot; Length: &quot; + i);

}

</FONT></PRE>
<P>Even when <TT>MyFunc</TT> changes the string, the result of the changes is reflected
in the calling 
module. This syntax passes a pointer to the function, but makes it
seem as though you are working with a local stack-based variable on both the caller
and calling sides.</P>
<P>Consider the following code samples:</P>
<PRE><FONT 
COLOR="#0066FF">MyAnsiString S = &quot;The road to the contagious hospital&quot;;

MyAnsiString S1 = AnsiString(&quot;If I had a green automobile...&quot;);

MyAnsiString S2(&quot;All that came out of them came quiet, like the four seasons&quot;);


ShowMessage(S + `\r' + S1 + `\r' + S2);

</FONT></PRE>
<P>It should be clear from looking at this code that the second example will take
longer to execute than the third, because it calls two constructors rather than just
one. You might also think 
that the first takes longer than the third. A logical course
of reasoning would be to suppose that, at minimum, it would have to call both a constructor
and the equals operator. In fact, when I stepped through the code, it became clear
that the 
compiler simply called the constructor immediately in the first example,
and that the machine code executed for the first and third examples was identical.</P>
<P>What is the lesson to be learned here? Unless you are writing a compiler, an operating

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -