注意:我想我会因此而发火,但是,对于 C++ 开发人员来说,这是一个 C++ 问题,所以...
哪些功能可以在 C 中完成,但不能在 C++ 中完成,您在使用 C++ 编码时最怀念哪些功能?
作为一名 C++ 开发人员,无论是 C99 还是其他语言,我都不会错过任何 C 语言。
我写这篇文章并不是出于恶意。 这是为错过一些 C/C99 功能的 C++ 开发人员提出的问题,因为他们忽略了 C++ 的基本功能。我确实相信这个问题及其答案忽略了 C++ 中可行或更好的替代方案(不,“C++ 向量很讨厌”的评论只是一个虚假的理由)。
这就是为什么我将在这里讨论每一个所谓的“缺失功能”......
变长数组?
可变长度数组是 C99 的语言特性。它的主要优点是:
- 堆栈分配
- 创建时可变长度
- 无需解除分配
对于最常见的情况,std::vector 将完成这项工作,并且无论如何都有更多功能。例如,除非我错了,否则变长数组有以下缺点:
- 堆栈上的分配意味着您不能从声明它的函数返回 VLA
- VLA 无法调整大小,这意味着如果它太小,那你就完蛋了
- VLA 必须在原型范围或块范围内声明。它不能是外部的或静态的。而且您不能将其声明为结构的成员。
- 它不能有初始化器
向量可以调整大小,并且可以返回。并且使用 C++0x(和 r 值引用),您可以使用移动语义返回一个向量,这意味着不需要无用的临时对象。你可以把它放在一个结构/类中,它可以是外部的,也可以是静态的。您可以使用默认值、数组的内容、容器或使用 C++0x 使用初始化列表来初始化它。
即使在那之后,如果你真的想要像 VLA 这样的东西,在 C++ 中,一个普通的 C++ 开发人员可以编写一个基于堆栈的类似向量的容器。 而且它不需要完整的语言委员会更新。
只是为了好玩,我碰巧发了一个answer with a simple proof-of-concept of a C++ VLA-like class。
C++ 的向量在大多数情况下是更好的选择,具有更多功能。在极少数情况下确实需要 VLA,它的功能可以通过用户定义的类来模拟。
将void * 转换为T *?
至于将任何void * 转换为另一个类型指针,这不是 C++ 中缺少的 C 特性:这是弱类型与强类型的选择
在 C++ 中也不是不可能做到这一点,而你可以通过强制转换来做到这一点。这种差异的关键在于降低 void * 不如其他语言有用的语言中的错误风险:在我当前的 C++ 100k 行项目中,void * 的出现次数为零。
指定的初始化器?
构造函数提供了更好的选择。
当然,你不可能直接初始化结构中的数据,但是,数据封装意味着大多数时候,我的对象中的数据是私有的,所以,使用指定的整个概念初始化它们的初始化器将是荒谬的。
对于类似 POD 的结构,构造函数很容易编写,并且可以处理指定的初始化程序永远不会做的情况(例如默认使用非零值初始化成员,甚至调用函数)。
由于 C++ 专注于数据封装,构造函数为指定初始化程序提供了更好的替代方案。
2011-11-05 编辑:
重读本节后,我想澄清一点:指定初始化器可能对非常有限的情况(即 POD)有用,这意味着虽然我不会错过它们(如所问在问题中),我不介意拥有它们。
复合字面量?
此句法糖再次假设您知道该结构的确切实现,并对其成员具有公共访问权限,而这在 C++ 中通常是您希望避免的。
再次重申,复合字面量不是函数、方法甚至构造函数无法处理的东西,具有额外功能的优势,如上所述。
声明变量名是 C++ 中的关键字,而不是 C 中的关键字?
我知道你的感受:每次我有可能在 C++ 中使用 interface、final 或 synchronized 时,我都会感到 Java 不寒而栗……
:-P
类型通用宏?
C 中的问题是你有很多函数,对不同的类型做相同的语义事情,这意味着每个函数必须有不同的名称。例如,根据 OpenGroup,确实存在以下功能:
double sin(double x);
float sinf(float x);
long double sinl(long double x);
- 等
来源:http://www.opengroup.org/onlinepubs/009695399/functions/sin.html
但是他们的名字很难记住,所以有人想到了。关于宏,它会使用编译器内置扩展来根据所使用参数的类型调用正确的宏。
这就是 C99 的<tgmath.h> 的全部魅力。
这个想法似乎很awesome,他们甚至添加了一个提议,为下一个 C 标准中的所有函数提供此功能,例如:
#define sin(x) __tgmath(x,,, \
float, sinf, long double, sinl, \
/* etc. */ \
, , sin)(x)
来源:http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1340.htm
现在,令人震惊的消息是:这个功能在 C++ 中已有几十年了:这被称为函数重载。
例如,上面的函数在 C++ 中声明为:
double sin (double x );
float sin (float x );
long double sin (long double x );
- 等
因此,“类型通用宏”是一种被破解的实现,它努力(部分)模拟更通用的 C++ 函数重载。
猜猜看:您甚至可以为自己的用户定义类型添加自己的重载。
结论
如上所示,每次我研究 C99 特性时,得出的结论都是:“嘿,我已经可以在 C++ 中做到了!” (通常在句子的某处加上“更好”这个词)。
说真的,作为一名 C++ 开发人员,我现在想念的是能够在工作中使用 C++0x。例如,以下 C++0x 特性:
auto
constexpr
- 初始化列表
- 右值参考
- lambdas
nullptr
- 等
整个“C++ 中缺少 C 的特性”是一个被高估的概念,我怀疑 C 开发人员(和 C 类开发人员)比 C++ 开发人员更感兴趣。