StupidBeauty
Read times:3525Posted at:Wed Oct 4 08:53:35 2017 - no title specified

《C++面向对象软件设计及构建》文章翻译:3.3匿名对象,3.3 Anonymous Objects

在某些情况下,只是临时需要某个对象。在这种情况下,可以避免为这个临时对象显式引入一个变量名,具体做法就是,创建一个 临时对象 ,它在各个方面来看,都是一个对象,只是,它没有名字。观摩以下示例:

Location initialLocation(100, 100),

displayLocation(200,200);

Shape    initialShape(150, 200),

displayShape(300, 200);

Frame window  (initialLocation, initialShape);

Frame display (displayLocation, displayShape);

...

Location newLocation(300,300);

Location newShape   (150,150);

window.MoveTo(newLocation);

display.Resize(newShape);


假设,所有的这些Location 和Shape 对象,除了在这个示例中的代码处使用之外,没有在其它任何地方被使用。

使用那些显式声明且有名字、却只被使用一次的对象,会有若干个坏处。第一,程序猿必须编写一条单独的声明语句,并且为某个对象想一个有意义的名字,而那个对象可能只扮演着微不足道的角色。这种传出,可能并不值得。第二,这个对象,可能会在它被用完之后仍然存在一段时间,而实际上我们并不需要它了。在上面的示例中,"initialLocation""window"的作用域是相同的。然而,我们需要window对象的时间要比需要那个Location 对象的时间长得多,可是两个对象却都是持续存在的。如果在那个Location 对象的有用生命周期结束之后,尽管销毁它,那么,在内存使用上的效率就更高。第三,日后阅读这砣代码的人,并未得到明确的指示,表明,像"initialLocation"和"displayLocation"这样的对象,实际上只是在一个狠小的地方使用的。只有完整地阅读了这个作用域中的所有代码之后,才能够得知,那些对象,是只被使用一次,还是日后会被再次使用。

匿名对象,即是一种更高效且明确的方式,以用于创建及使用某个只在单个小地方使用的对象。临时对象,是在我们所需要它的地方直接构造的。

以上示例,可利用匿名对象改写成以下形式:

Frame window  ( Location(100,100), Shape(150, 200) );

Frame display ( Location(200,200), Shape(300, 200) );

...

window.MoveTo( Location(300,300) );

display.Resize( Shape(150,150) );


在构造window 对象的过程中,创建了两个匿名对象:一个匿名的Location对象和一个匿名的Shape对象display对象,也是利用两个匿名对象创建的。最后,MoveToResize操作中也使用了匿名对象。有一点狠重要,那就是,妳需要意识到,那个使用带名字对象和示例,和这个使用匿名对象的示例,其执行效果是相同的。

匿名对象,还可以用来为某个并非是内置数据类型的类的对象提供参数默认值。例如,Frame 类中的MoveTo 方法,需要一个Location 对象作为它的参数。如果需要为这个参数指定默认值,那么,可以这样写:

class Frame {

private:

...

public:

...

void MoveTo (Location loc = Location(10,10));

...

};

MoveTo 方法的这个定义,指定了,如果在调用MoveTo 方法时未提供参数,那么,会使用默认的Location 对象(10,10)。

另外,匿名对象还可以用于为某个对象赋予新的值。假设,某个Frame 对象,名为"window",在创建时使用了某个Location 对象,名为"current"。我们需要将这个Frame 在屏幕上移动一定数量(各个方向上移动五个像素)的相对位置。我们需要的,就是某个可用来更新这个Location 对象的方式。然而,Location类中,并未定义任何一个可对 Location 对象的数值进行更新的设值方法 - 只能对它们进行构造及查询。在以下代码示例中,展示了三种利用匿名对象来达成这一效果的方法。

// 第一 个示例

Location current(100,100);

Frame window  (current);

...

window.MoveTo( Location(current.XCoord()+5, current.YCoord()+5) );


第一个示例,展示了,可利用一个已有的对象的信息来构造一个匿名对象。在这个示例中,使用Location 类中定义的查询方法对current 这个Location 对象进行了查询,并使用查询结果来定义一个新的匿名Location 对象的构造函数参数。

// 第二 个示例

Location current(100,100);

Frame window  (current);

...

current = Location(105,105);

window.MoveTo( current );


在第二个示例中,使用新的坐标值创建了一个匿名对象,并将它赋值给名为current 的对象。对象赋值,是一个简单的、字节级别的复制操作:每个对象都位于某块内存中。在默认的赋值操作中,会使用赋值操作符右侧的对象所占用的内存处的那些字节,覆盖掉赋值操作符左侧的对象(current)所占用的内存处的那些字节。在这种情况下,默认对象赋值操作,就与"x = 10"这种赋值完全类似了。后者,会使用10 这个值的比特模式,覆盖掉变量 x 所处的内存。

// 第三 个示例

Location current(100,100);

Frame window  (current);

...

current = Location(current.XCoord()+5, current.YCoord()+5);

window.MoveTo( current );


在第三个示例中,针对对象使用了类似于我们会对普通变量所使用的赋值技巧,"x = x + 1",在这种用法中,使用某个已有变量的值来计算出某个新的值,那个新的值又再次被赋值给该变量。类似地,使用Location 类中定义的查询方法,查询到了current 对象的值,然后计算出一个新的值(即为代码中的匿名Location对象),再将那个新的值赋值给current 对象。这个示例与第二个示例的 区别在于,不需要知道新的Location 对象的绝对坐标 - 会根据该Location 对象已有的值来进行相对性的计算。

注意,匿名对象的使用,消除了上面所说的三个问题。首先,对象匿名对象,无需进行单独的声明。它们就是在自己被用到的地方创建的,无需使用标识名字。第二,这个对象,只会在需要的时候被构造,并在用完它的时候会立即销毁。这样,就将匿名对象的生命周期缩短到最短的情况,并减少了它的资源占用。第三,明确地告知后面的代码阅读得,这个匿名对象,不会在其它地方使用 - 不可能在其它地方使用的,因为没有任何方式能够引用到这个对象。

任务

  1. 1. 仅使用匿名对象,编写一个声明语句,声明一个Frame 对象,位于坐标(50,50)处,宽度为200,高度为300。

  2. 2. 仅使用一个匿名对象,编写一行代码,将某个以变量名"window"标识的Frame 移动到坐标(100,100)处。

  3. 3. 仅使用一个匿名对象,编写一行代码,将某个以变量名"window"标识的Frame的尺寸改变为宽度200、高度300。

  4. 4.假设,某个Frame 对象,以变量名"window"标识。它当前位于以变量名"position"标识的Location 对象所表示的坐标处。使用一个匿名对象,编写一行代码,将该个Frame 对象移动,向右10 个像素,向下50 个像素。

  5. 5.假设,某个Frame 对象,以变量名"window"标识。当前,它的尺寸等于以变量名"size"标识的Shape 对象所给出的尺寸。使用一个匿名对象,编写一行代码,改变这个Frame 对象的大小,让它变宽50个像素,变矮50个像素。

未知美人

http://www.917ii.com/bbs/data/attachment/forum/201403/04/111718x36hsh038k7lv1za.jpg

Your opinions
Your name:Email:Website url:Opinion content:
- no title specified

HxLauncher: Launch Android applications by voice commands