📄 tij0128.html
字号:
fq = q;
seeds = seedCount;
s = <font color="#0000ff">new</font> Seed[seeds];
<font color="#0000ff">for</font>(<font color="#0000ff">int</font> i = 0; i < seeds; i++)
s[i] = <font color="#0000ff">new</font> Seed();
}
<font color="#009900">// Other constructors:</font>
<font color="#009900">// ...</font>
<font color="#009900">// Copy constructor:</font>
Fruit(Fruit f) {
fq = <font color="#0000ff">new</font> FruitQualities(f.fq);
seeds = f.seeds;
<font color="#009900">// Call all Seed copy-constructors:</font>
<font color="#0000ff">for</font>(<font color="#0000ff">int</font> i = 0; i < seeds; i++)
s[i] = <font color="#0000ff">new</font> Seed(f.s[i]);
<font color="#009900">// Other copy-construction activities...</font>
}
<font color="#009900">// To allow derived constructors (or other </font>
<font color="#009900">// methods) to put in different qualities:</font>
<font color="#0000ff">protected</font> <font color="#0000ff">void</font> addQualities(FruitQualities q) {
fq = q;
}
<font color="#0000ff">protected</font> FruitQualities getQualities() {
<font color="#0000ff">return</font> fq;
}
}
<font color="#0000ff">class</font> Tomato <font color="#0000ff">extends</font> Fruit {
Tomato() {
<font color="#0000ff">super</font>(<font color="#0000ff">new</font> FruitQualities(), 100);
}
Tomato(Tomato t) { <font color="#009900">// Copy-constructor</font>
<font color="#0000ff">super</font>(t); <font color="#009900">// Upcast for base copy-constructor</font>
<font color="#009900">// Other copy-construction activities...</font>
}
}
<font color="#0000ff">class</font> ZebraQualities <font color="#0000ff">extends</font> FruitQualities {
<font color="#0000ff">private</font> <font color="#0000ff">int</font> stripedness;
ZebraQualities() { <font color="#009900">// Default constructor</font>
<font color="#009900">// do something meaningful...</font>
}
ZebraQualities(ZebraQualities z) {
<font color="#0000ff">super</font>(z);
stripedness = z.stripedness;
}
}
<font color="#0000ff">class</font> GreenZebra <font color="#0000ff">extends</font> Tomato {
GreenZebra() {
addQualities(<font color="#0000ff">new</font> ZebraQualities());
}
GreenZebra(GreenZebra g) {
<font color="#0000ff">super</font>(g); <font color="#009900">// Calls Tomato(Tomato)</font>
<font color="#009900">// Restore the right qualities:</font>
addQualities(<font color="#0000ff">new</font> ZebraQualities());
}
<font color="#0000ff">void</font> evaluate() {
ZebraQualities zq =
(ZebraQualities)getQualities();
<font color="#009900">// Do something with the qualities</font>
<font color="#009900">// ...</font>
}
}
<font color="#0000ff">public</font> <font color="#0000ff">class</font> CopyConstructor {
<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> ripen(Tomato t) {
<font color="#009900">// Use the "copy constructor":</font>
t = <font color="#0000ff">new</font> Tomato(t);
System.out.println("In ripen, t is a " +
t.getClass().getName());
}
<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> slice(Fruit f) {
f = <font color="#0000ff">new</font> Fruit(f); <font color="#009900">// Hmmm... will this work?</font>
System.out.println("In slice, f is a " +
f.getClass().getName());
}
<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) {
Tomato tomato = <font color="#0000ff">new</font> Tomato();
ripen(tomato); <font color="#009900">// OK</font>
slice(tomato); <font color="#009900">// OOPS!</font>
GreenZebra g = <font color="#0000ff">new</font> GreenZebra();
ripen(g); <font color="#009900">// OOPS!</font>
slice(g); <font color="#009900">// OOPS!</font>
g.evaluate();
}
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">This
seems a bit strange at first. Sure, fruit has qualities, but why not just put
data members representing those qualities directly into the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Fruit</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
class? There are two potential reasons. The first is that you might want to
easily insert or change the qualities. Note that
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Fruit</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
has a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>protected</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>addQualities( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method to allow derived classes to do this. (You might think the logical thing
to do is to have a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>protected</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
constructor in
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Fruit</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
that takes a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>FruitQualities</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
argument, but constructors don’t inherit so it wouldn’t be
available in second or greater level classes.) By making the fruit qualities
into a separate class, you have greater flexibility, including the ability to
change the qualities midway through the lifetime of a particular
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Fruit</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
second reason for making
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>FruitQualities</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
a separate object is in case you want to add new qualities or to change the
behavior via inheritance and polymorphism. Note that for
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>GreenZebra</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
(which really is a type of tomato – I’ve grown them and
they’re fabulous), the constructor calls
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>addQualities( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and passes it a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ZebraQualities</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object, which is derived from
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>FruitQualities</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
so it can be attached to the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>FruitQualities</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
handle in the base class. Of course, when
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>GreenZebra</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
uses the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>FruitQualities</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
it must downcast it to the correct type (as seen in
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>evaluate( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">),
but it always knows that type is
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ZebraQualities</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">You’ll
also see that there’s a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Seed</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
class, and that
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Fruit</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
(which by definition carries its own seeds) contains an array of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Seed</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">s.</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Finally,
notice that each class has a copy constructor, and that each copy constructor
must take care to call the copy constructors for the base class and member
objects to produce a deep copy. The copy constructor is tested inside the class
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>CopyConstructor</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
The method
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ripen( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
takes a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Tomato
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">argument
and performs copy-construction on it in order to duplicate the object:
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">t
= new Tomato(t);
</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">while
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>slice( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
takes a more generic
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Fruit</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object and also duplicates it:
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">f
= new Fruit(f);
</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">These
are tested with different kinds of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Fruit</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>main( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
Here’s the output:
</FONT><P></DIV>
<font color="#990000"><PRE>In ripen, t is a Tomato
In slice, f is a Fruit
In ripen, t is a Tomato
In slice, f is a Fruit </PRE></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">This
is where the problem shows up. After the copy-construction that happens to the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Tomato</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
inside
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>slice( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
the result is no longer a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Tomato</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object, but just a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Fruit</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
It has lost all of its tomato-ness. Further, when you take a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>GreenZebra</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
both
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ripen( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>slice( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
turn it into a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Tomato</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Fruit</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
respectively. Thus, unfortunately, the copy constructor scheme is no good to us
in Java when attempting to make a local copy of an object.
</FONT><P></DIV>
<A NAME="Heading382"></A><H4 ALIGN=LEFT>
Why
does it work in C++ and not Java?
</H4>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
copy constructor is a fundamental part of C++, since it automatically makes a
local copy of an object. Yet the example above proves that it does not work for
Java. Why? In Java everything that we manipulate is a handle, while in C++ you
can have handle-like entities and you can
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>also</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
pass around the objects directly. That’s what the C++ copy constructor is
for: when you want to take an object and pass it in by value, thus duplicating
the object. So it works fine in C++, but you should keep in mind that this
scheme fails in Java, so don’t use it.
</FONT><a name="_Toc375545433"></a><a name="_Toc408018669"></a><P></DIV>
<div align="right">
<a href="tij_c.html">Contents</a> | <a href="tij0127.html">Prev</a> | <a href="tij0129.html">Next</a>
</div>
</body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -