如果我在我的C ++项目中使用C风格强制转换,是否值得重构C ++强制转换?

我在我的15K LOC C ++项目中使用C风格的演员,90%的时间在儿童和基础class之间进行演员训练。

即使当我读到使用它们是不好的,而且它们可能导致严重的错误,因为它们不像C ++types那样安全,我仍然感觉使用它们是非常好的和舒适的。

到目前为止,我的项目中还没有遇到一个错误,例如,由于意外错误input了C-Style演员而导致的错误。

有两个主要的原因我没有使用它们:

  • 我还不够了解他们
  • 我不喜欢他们的语法,他们更冗长,更难以阅读

我的问题:

  • (为什么)我应该重构我的项目使用C ++风格的演员?
  • 我为什么要为未来的项目使用C ++风格的演员?

我使用C ++为我提供的所有其他优点,包括虚拟和抽象基类,名称空间,STL等OOP,而不是新types的转换语法。 “ 为什么你不只是用C呢? ”这个说法不适合我。

正如你所提到的,C ++风格types的主要优点是types安全性。 C ++中的每个转换都会处理一种特定types的转换(或一系列相关的转换),因此编译器可以检查您是否意外执行了更多转换,或者转换过程从根本上不安全。

有一点需要思考的是,尽pipe使用C风格的演员感觉很好,虽然你没有犯过错误是件好事,但从事代码基础工作的其他人可能不太喜欢这些演员就像你一样。 使用铸造操作符使代码更加自我logging。 如果你在某个地方有C风格的演员,其他读者可能无法立即推断出你在做什么。 如果他们看到类似的东西

T* ptr = (T*) var; 

他们可能不会马上知道这是否是

  1. 从基类转换到派生类或其他方式。
  2. 强制转换closuresvar const
  3. 从整型转换为指针

虽然他们可以从上下文中收集这些信息,但是如果您使用类似的转换,则会发生什么情况更为明显

 T* ptr = static_cast<T*>(var); 

要么

 T* ptr = const_cast<T*>(var); 

selectC ++风格的转换操作符的另一个原因是它们使得代码更易于改变。 例如,假设我有这个function:

 void DoSomething(Base* ptr) { Derived* derived = (Derived *) ptr; DoSomethingElse(derived); } 

现在,假设我意识到这个函数不应该改变它的参数,所以我决定把它标记为const 。 例如:

 void DoSomething(const Base* ptr) { Derived* derived = (Derived *) ptr; DoSomethingElse(derived); } 

但是现在我们遇到了一个问题,那就是过去只是沮丧的C风格的演员,也剥夺了一些常识。 这可能会导致一个简单的错误,即DoSomethingElse突变了我传入的指针,即使DoSomething方法本身承诺不执行此操作。 如果相反,我写这个代码为

 void DoSomething(Base* ptr) { Derived* derived = static_cast<Derived *>(ptr); DoSomethingElse(derived); } 

然后通过添加const改变代码:

 void DoSomething(const Base* ptr) { Derived* derived = static_cast<Derived *>(ptr); DoSomethingElse(derived); } 

现在,我会得到一个编译器错误,告诉我我的旧转换已经损坏,这可能会导致我发现代码中存在逻辑错误(即DoSomethingElse突变了它的参数,所以我不能天真地使ptr成为指向const

简而言之,使用C ++types转换操作符使代码更具可读性,更易于维护。 它使代码背后的逻辑更加明确。 而且,通过让编译器捕捉错误,使得代码更容易出错。 我会build议在未来使用C ++风格的转换运算符,这些主要原因。

至于你是否应该回去尝试用C ++风格的演员replace你当前的C风格演员,这真的取决于你。 作为一个练习,我build议你只是练习学习你正在使用什么types的演员。 此外,你可能会发现一个逻辑错误,这将使search值得您的时间!

在我曾经工作的公司中,我们曾经不得不将一百万行代码应用程序移植到一个新的平台上。 开始时,“只是另一个Unix平台的另一个端口”(代码已经在Windows,OSX和六个类似Unix的平台上运行),结果是一个巨大的问题。 IIRC,原因是这个平台有比较严格的alignment要求 ,我们的一些演员由于错位导致硬件exception

如果不是因为这些演员中有一定比例的演员是C型演员 ,那么这个问题就很容易解决。 这是不可能的。 search字面上成千上万的代码行 ,都必须由人类手动检查 ,其中99.99%是完全不相关的。
这并不意味着我们人类往往会错过这些难以发现的演员阵容,而这些演员阵容将不得不在另外一轮回顾成千上万的代码行中find,其中99.99%完全相同第一轮。

这个任务几乎不可能完成, 几乎打破了公司的背后 ,因为如果我们放弃了最后期限,他们将面临严重的合同罚款。

不用说,之后决定用C ++对应的C代替所有的C风格。 但是,在我们必须build造这个港口之前,这个政策是否存在?

(为什么)我应该重构我的项目使用C ++风格的演员?

是。 出于同样的原因,你应该在将来使用它们。

我为什么要为未来的项目使用C ++风格的演员?

这份名单实际上是相当长的,但我会重申最重要的。

首先,他们明确表示演员的意图。 读“static_cast”你知道作者打算执行一个静态转换,而不是一个reinterpret或const。

其次,他们做一个,只有一个。 例如,你不能无意中抛弃const。

他们很容易search。 search“const_cast”以查找所有强制转换为/从const。 你怎么用C风格做这个? 你不能。

当本地代码语义改变时,它们不会改变types。 例如,如果Widget停止从指向的任何types的blahinheritance, (Widget*)(blah)将默默地更改为reinterpret强制转换。 如果Widget定义不在本地可用,它也会更改为重新parsing强制转换。 如果你使用新式的转换,你会得到编译器呕吐,而不是沉默地重新解释陈述。

你可以做一个dynamic的演员。 C风格的演员不能做到这一点。

好吧两部分:

(为什么)我应该重构我的项目使用C ++风格的演员?

如果你的代码工作。 那么不要修复它。 保持原状。 无论如何,findC会非常困难。 如果您正在编写代码并碰到C语言代码,请根据需要进行更改。

我为什么要为未来的项目使用C ++风格的演员?

因为C剧组很容易出错。

如果90%的演员是从小class级到基级class的,那么将他们转移出去将是一个开始 – 他们不应该被需要。 如果你有很多从底部到底部的投射,那么你还在做其他的事情。

剩下的,你告诉编译器有什么奇怪的事情正在发生,你违反了规则 – 无论是reinterpret_cast或const_casttypes系统的规则,你冒着代表static_cast到一个较小的整型,或者你打破了LSP,并且在给定基类时必须知道子类的具体types。

明确这些情况是件好事。

 (Why) Should I refactor my project to use C++-style casts? Why should I use C++-style casts for my future projects? 

关于这个问题的第二个问题有一些很好的答案(包括我自己的IMO) 。

对于第一个问题,如果我处于你的位置,那么只要我已经编辑了一个文件,就会用C ++types转换替代Ctypes转换。 编辑所有代码并重新编译它可能不值得花一天左右的时间,但是当您已经在编写代码时,可能需要逐步改进您的代码库。

如果你有时间留待重新考虑活动,这将是一个很好的候选人。

如果我是你,我会继续使用C型的演员。 你有充分的理由:你没有经历C风格演员的所谓缺陷,C ++演员更加冗长,C ++演员难以阅读,而且对你不太熟悉。

更一般地说,作为一名C ++程序员,你会经常阅读或被告知某种做事的方式是做事的方式是旧的,错误的,而且你应该使用新的,正确的,C ++的做事方式。 一些例子:

  • 你应该使用C ++风格转换而不是C风格转换
  • 你应该使用引用而不是指针
  • 你应该使用“const”关键字
  • 你应该使用generics而不是void指针或者types转换
  • 你应该使用初始化列表,而不是在构造函数体中初始化成员variables
  • 您应该使用构造函数而不是构build后初始化函数
  • 你不应该使用macros

通常你会被告知新的方法更安全,它可以让编译器捕获更多的错误,并使代码更清晰。

我build议你怀疑这样的build议。 相反,请考虑:使用新的C ++function是否解决了您实际存在的问题? 它会产生新的问题吗(顺便说一句,代码冗长和可读性下降是问题)? 如果对第一个问题的答案是否定的,或者对第一个问题的答案是肯定的,那么应该考虑坚持旧的,错误的,C的方式。

对代码清晰度的一个侧面评论:如果添加的文本不能帮助读者理解程序,则详细程度会降低清晰度。 如果我是你,我会认为C ++风格的转换会怀疑地改善代码的清晰度,因为你是程序的读者,不会感受到好处。

我曾经是那种总是试图使用New,Correct,C ++方式的人。 我不再那么教条。 下面的链接是改变我的想法的一个重要因素。

http://yosefk.com/c++fqa/