Top Ten Traps in C# for C++ Programmers中文版(转)(2)

c++|中文

陷阱六.虚方法必须被显式重载

在C#中,如果程序员决定重载一个虚方法,他(她)必须显式使用override关键字。

让我们考察一下这样做的好处。假定公司A写了一个Window类,公司B购买了公司A的Window类的一个拷贝作为基类。公司B的程序员从中派生【译注:原文为...using...,从下文来看,显然是“派生”之意。事实上,使用类的方式还有“组合”(也有说为“嵌入”或“包容”(COM语义)等等),后者不存在下文所描述的问题】出ListBox类和RadioButton类。公司B的程序员不知道或不能控制Window类的设计,包括公司A将来对Window类可能做的修改。

现在假定公司B的程序员决定为ListBox类加入一个Sort方法:

public class ListBox : Window

{

public virtual void Sort() {}

}

这是没有问题的—直到公司A的Window类作者发布了Window类的版本2,公司A的程序员向Window类也加入了一个public的Sort方法:

public class Window

{

public virtual void Sort() {}

}

在C++中,Window类新的虚方法Sort将会作为ListBox虚方法的基类方法。当你试图调用Window的Sort时,实际上调用的是ListBox的Sort。C#中虚方法【译注:原文写成virtual function】永远被认为是虚拟调度的根。这就是说,只要C#找到了一个虚方法,它就不会再沿着继承层次进一步寻找了,如果一个新的Sort虚方法被引入Window,ListBox的运行时行为不会被改变。当ListBox再次被编译时,编译器会发出如下警告:

"\class1.cs(54,24): warning CS0114: 'ListBox.Sort()' hides inherited member 'Window.Sort()'.

如果要使当前成员重载实现,可加入override关键字。否则,加上new关键字。

如果想要移去这个警告,程序员必须明确指明他的意图。可以将ListBox的Sort方法标为new,以指明它不是对Window的虚方法的重载:

public class ListBox : Window

{

public new virtual void Sort() {}

}

这样编译器就不会再警告。另一方面,如果程序员想重载Window的方法,只要显式加上override关键字即可。

陷阱七:不可以在头部进行初始化

C#里的初始化不同于C++。假定你有一个类Person,它有一个私有成员变量age;一个派生类Employee,它有一个私有成员变量salaryLeverl。在C++中,你可以在Employee构造器的成员初始化列表部分初始化salaryLevel:

Employee::Employee(int theAge, int theSalaryLevel):

Person(theAge) // 初始化基类

salaryLevel(theSalaryLevel) // 初始化成员变量

{

// 构造器体

}

在C#中,这个构造器是非法的。尽管你仍可以如此初始化基类,但对成员变量的初始化将导致一个编译时错误。你可以在成员变量声明处对其赋初始值:

Class Employee : public Person

{

// 在这儿声明

private salaryLevel = 3; //初始化

}

【译注:以上代码有误LC#中,正确写法如下:

class Employee: Person

{

private int salaryLevel = 3;

}

你不需要在每一个类声明的后面都加上一个分号。每一个成员都必须要有显式的访问级别声明。

陷阱8.不能把布尔值转换为整型值

在C#中,布尔值(true、false)不同于整型值。因此,不能这么写:

if ( someFuncWhichReturnsAValue() )//【译注:假定这个方法不返回布尔值】

也不能指望如果someFuncWhichReturnsAValue返回一个0它将等于false,否则为true。一个好消息是误用赋值操作符而不是相等操作符的老毛病不会再犯了。因此,如果这么写:

if ( x = 5 )

将会得到一个编译时错误,因为x = 5的结果为5,而它不是布尔值。

【译注:以下是C++里一不小心会犯的逻辑错误,编译器不会有任何提示L运行得很顺畅,不过结果并不是你想要的:

C++:

#include "stdafx.h"

int main(int argc, char* argv[])

{

int n = 0;

if (n = 1)//编译器啥都没说L一般推荐写为1 == n,万一写成1 = n编译器都不同意J

{

printf("1\n");

}

else

{

printf("0\n");

}

return 0;

}

以上运行结果为1,这未必是你想要的。

C#:

using System;

public class RyTestBoolApp

{

public static void Main()

{

int n = 0;

if (n = 1)//编译器不同意J无法将int转换成bool

{

Console.WriteLine("1");

}

else

{

Console.WriteLine("0");

}

}

}

但如果是这种情况:

bool b = false;

if (b = true)

...

不管是C++还是C#都没招L

【译注:C++程序员一般是喜欢这种自由的写法:

if (MyRef)

if (MyInt)

但在C#里,必须写成:

if (MyRef != null)//或if (null != MyRef)

if (MyInt != 0)//或if (0 != MyInt)

等。

陷阱九.switch语句不可“贯穿”【译注:即fall through,Beta2的联机文档就是如此译法】

在C#中,如果在case语句里有代码的话,那它就不可“贯穿”到下一句。因此,尽管下面代码在C++里合法,但在C#中则不然:

switch (i)

{

case 4:

CallFuncOne();

case 5: // 错误,不可以“贯穿”

CallSomeFunc();

}

为了达到这个目的,需要显式地使用goto语句:

switch (i)

{

case 4:

CallFuncOne();

goto case 5;

case 5:

CallSomeFunc();

}

如果case语句没做任何事(里面没有代码)就可以“贯穿”:

switch (i)

{

case 4: // 可以“贯穿”

case 5: // 可以“贯穿”

case 6:

CallSomeFunc();

}

【译注:以下是使用switch的完整例子,它还说明了switch语句的参数类型可以是字符串,此例同时还演示了属性的使用方法。

using System;

class RySwitchTest

{

public RySwitchTest(string AStr)

{

this.StrProperty = AStr;

}

protected string StrField;

public string StrProperty

{

get

{

return this.StrField;

}

set

{

this.StrField = value;

}

}

public void SwitchStrProperty()

{

switch (this.StrProperty)

{

case ("ry01"):

Console.WriteLine("ry01");

break;

case ("ry02"):

Console.WriteLine("ry02");

break;//如果这一行注释掉,编译器会报控制不能从一个case标签(case "ry02":)贯穿到另一个标签,如果你确实需要,可以这么写:goto case ("ry03");或goto default。

case ("ry03"):

Console.WriteLine("ry03");

break;

default:

Console.WriteLine("default");

break;

}

}

}

class RySwitchTestApp

{

public static void Main()

{

RySwitchTest rst = new RySwitchTest("ry02");

rst.SwitchStrProperty();

}

}

陷阱十.C#需要明确的赋值操作

C#要求必须明确地进行赋值操作,这就意味所有变量在使用前必须被赋值。因此,尽管你可以声明未初始化的变量,但在它拥有值之前是不可以被传递到方法的。

这就引出了一个问题—当你仅仅是想将变量用作一个“出”参数按引用传递给方法时。例如,假定有个方法,返回当前的小时、分钟和秒。如果这么写:

int theHour;

int theMinute;

int theSecond;

timeObject.GetTime( ref theHour, ref theMinute, ref theSecond)

编译将出错,因为在使用theHour、theMinute和theSecond前,它们没有被初始化:

Use of unassigned local variable 'theHour'

Use of unassigned local variable 'theMinute'

Use of unassigned local variable 'theSecond'

可以将它们初始化为0或者其它什么无伤大雅的值以让讨厌的编译器安静下来:

int theHour = 0;

int theMinute = 0;

int theSecond = 0;

timeObject.GetTime( ref theHour, ref theMinute, ref theSecond)

但是这种写法实在太愚蠢!我们的本意不过是想把这些变量按引用传递到GetTime,在其中改变它们的值。为了解决这个问题,C#提供了out参数修饰符。这个修饰符避免了对引用参数也要初始化的需求。例如,为GetTime提供的参数没有提供给方法任何信息,它们仅仅是想从方法里取得信息。因此,把这三个参数都标记为out型的,就避免了在方法外初始化它们的需要。但当从被传入的方法返回时,out参数必须被赋值。下面是改变后的GetTime参数声明:

public void GetTime(out int h, out int m, out int s)

{

h = Hour;

m = Minute;

s = Second;

}

下面则是对GetTime方法的新的调用方式:

timeObject.GetTime( out theHour, out theMinute, out theSecond);

【译注:完整示例如下:

C#:[例1:使用ref修饰的方法参数]

using System;

class RyRefTest

{

public RyRefTest()

{

this.IntField = 1;

this.StrField = "StrField";

}

protected int IntField;

protected string StrField;

public void GetFields(ref int AInt, ref string AStr)

{

AInt = this.IntField;

AStr = this.StrField;

}

}

class RyRefTestApp

{

public static void Main()

{

RyRefTest rrt = new RyRefTest();

int IntVar = 0;//如果是int IntVar; 编译器会报使用了未赋值的变量IntVar

string StrVar = "0";//如果是string StrVar; 编译器会报使用了未赋值的变量StrVar

rrt.GetFields(ref IntVar, ref StrVar);

Console.WriteLine("IntVar = {0}, StrVar = {1}", IntVar, StrVar);

}

}

C#:[例2:使用out修饰的方法参数]

using System;

class RyRefTest

{

public RyRefTest()

{

this.IntField = 1;

this.StrField = "StrField";

}

protected int IntField;

protected string StrField;

public void GetFields(out int AInt, out string AStr)

{

AInt = this.IntField;

AStr = this.StrField;

}

}

class RyRefTestApp

{

public static void Main()

{

RyRefTest rrt = new RyRefTest();

int IntVar;//这样就可以了,如果写成int IntVar = 0;当然也没问题J

string StrVar; //这样就可以了,如果写成string StrVar = "0";当然也没问题J

rrt.GetFields(out IntVar, out StrVar);

Console.WriteLine("IntVar = {0}, StrVar = {1}", IntVar, StrVar);

}

}

时间: 2024-10-20 07:28:14

Top Ten Traps in C# for C++ Programmers中文版(转)(2)的相关文章

Top Ten Traps in C# for C++ Programmers中文版(转)

c++|中文 [译序:C#入门文章.请注意:所有程序调试环境为Microsoft Visual Studio.NET 7.0 Beta2和 Microsoft .NET Framework SDK Beta2.限于译者时间和能力,文中倘有讹误,当以英文原版为准] 在最近发表于<MSDN Magazine>(2001年7月刊)上的一篇文章里,我讲了"从C++转移到C#,你应该了解些什么?".在那篇文章里,我说过C#和C++的语法很相似,转移过程中的困难并非来自语言自身,而是对

Top Ten One-Liners from CommandLineFu Explained

I love working in the shell. Mastery of shell lets you get things done in seconds, rather than minutes or hours, if you chose to write a program instead. In this article I'd like to explain the top one-liners from the commandlinefu.com. It's a user-d

【MOS】Top Ten Performance Mistakes Found in Oracle Systems. (文档 ID 858539.1)

In this Document Purpose Troubleshooting Steps References APPLIES TO: Oracle Database - Enterprise Edition - Version 9.2.0.8 and laterInformation in this document applies to any platform.RDBMS PURPOSE The purpose of this note is to inform reader abou

[vim]Best of Vim Tips

zzapper's Tips Page ------------------------------------------------------------------------------__BEGIN__------------------------------------------------------------------------------# searching/joe/e                      : cursor set to End of mat

国外优秀开源PHP建站程序一览

大量的PHP开源(开放源代码/Open Source)应用改变了这个世界,改变了互联网,以下我们总结从数据库到购物.博客等众多类型的开源PHP软件,供网站开发者们参考. 博客:WordPress WordPress是使用PHP开发的著名博客平台,免费开源,功能强大,不仅仅用于博客搭建,还可以广泛应用于各类网络信息发布平台. 论坛:phpBB phpBB是一种广泛流行的开源论坛软件,具有易于使用的管理面板和友好的用户安装界面,可以轻松地在数分钟内建立起一个论坛,功能上具有很高的可配置性,能够完全定

十大最佳WordPress插件推荐

WordPress是使用PHP语言和MySQL数据库开发的一个极为流行的Blog(博客.网志)系统,功能非常强大,插件和模板众多,易于扩充功能.安装和使用都非常方便.目前WordPress已经成为主流的Blog搭建平台. WordPress Plugin扩展插件众多,使用这些插件可以轻松的扩展和定制WordPress的功能,由于WordPress插件实在太多,因此对于初学者来说会看得眼花缭乱,因此我这里就介绍十个我自己觉得不错的WordPress插件,我挑选的规则是插件的功能要实用且高效,有些插

国外网站设计资源推荐

国外网站|设计|设计资源 CSS库 做设计的时候总是容易没有灵感.到CSS库去看看别人做得设计也许会帮你找到不少灵感.如果你的设计足够优秀让这些CSS库收录的话,那么这还会为你带来很多访问者 Unmatchedstyle cssBeauty cssvault Stylegala CSS Drive css thesis Styleboost CSSElite CSS Import Web Creme CSS Mania DesignShack  Web标准 遵守Web标准来编写代码会使你的代码干

博客可用性:十大错误设计

写在前面的话:本文将介绍一些关于博客可用性(Weblog Usability)的十个最常见的错误.本文为翻译作品,之所以我要花一晚上的时间翻译这篇文章,因为我看完此文后颇有一些感慨,为了让更多的人了解这篇文章,我将这篇文章进行了翻译,并附加上我自己的观点.初次翻译,翻译的不好,见谅. 博客可用性:十大错误设计 作者:Jakob Nielsen, 翻译:William Long 博客是网站的一种形态,因此对于网站易用性的一些指导方针同样适用于博客,但是博客是一种特殊类型的网站,他们的一些独特的特性

最常用的10个javascript自定义函数

javascript|函数 If there was ever a universal common.js shared among the entire develosphere, you'd fine these ten (plus one bonus) functions. It would be the swiss army knife no developer would go into production without. They have no doubt been teste