在讨论“隐藏功能”问题时,没有关于C++的爱吗?我想我应该提出这个问题。C++有哪些隐藏功能?
在讨论“隐藏功能”问题时,没有关于C++的爱吗?我想我应该提出这个问题。C++有哪些隐藏功能?
大部分 C++ 程序员都熟悉三目运算符:
x = (y < 0) ? 10 : 20;
然而,他们并没有意识到它可以被用作 lvalue:
(a == 0 ? a : b) = 1;
这是一个简写,意为
if (a == 0)
a = 1;
else
b = 1;
请小心使用 :-)
(value ? function1 : function2)()
。 - Chris Burt-Brownfunction1
和function2
会被隐式转换为函数指针,然后将结果隐式转换回去。 - MSalters您可以在C++源代码中放置URI而不会出错。例如:
void foo() {
http://stackoverflow.com/
int bar = 4;
...
}
goto
语句,在 C++ 中可以使用)。两个斜杠后面的任何内容都是注释。因此,在 http://stackoverflow.com
中,http
是一个标签(理论上您可以编写 goto http;
),而 //stackoverflow.com
只是一条行末注释。这两者都是合法的 C++ 代码,所以这个结构可以编译通过。当然,它并没有做任何有用的事情。 - David Thornley我同意大多数帖子的观点:C++是一种多范式语言,所以你会发现“隐藏”的功能(除了应该尽量避免的“未定义行为”之外)都是设施的巧妙使用。
这些设施中的大部分都不是语言内置功能,而是基于库的。
最重要的是RAII,它经常被来自C世界的C++开发人员忽视多年。 运算符重载通常是一个被误解的功能,它可以实现类似数组的行为(下标运算符),指针般的操作(智能指针)和类似内置操作(矩阵乘法)。
使用异常通常很困难,但通过一些工作,可以通过异常安全规范产生非常健壮的代码(包括不会失败的代码,或者具有提交样式功能的代码,即将成功或恢复到其原始状态)。
C++最著名的“隐藏”功能是模板元编程,因为它使您能够在编译时部分(或完全)执行程序,而不是在运行时执行。不过,这很困难,您必须在尝试之前对模板有牢固的掌握。
其他使用多范式的方式产生“编程方式”超出了C++的祖先,即C。
通过使用函数对象,您可以模拟函数,并具有附加的类型安全性和状态。使用命令模式,您可以延迟代码执行。大多数其他设计模式都可以在C++中轻松高效地实现,以产生不应在“官方C++范例”列表中的替代编码风格。
通过使用模板,您可以生成适用于大多数类型(包括您最初想到的类型之外的类型)的代码。您还可以增加类型安全性,就像自动类型安全的malloc / realloc / free一样。C ++对象特性非常强大(因此,如果不小心使用,可能很危险),但是即使在C ++中,动态多态性也有其静态版本:CRTP。我发现Scott Meyers的大多数“Effective C ++”类型的书籍或Herb Sutter的“Exceptional C ++”类型的书籍都很容易阅读,并且对C ++的已知和未知特性提供了宝贵的信息。
我最喜欢的之一应该会让任何Java程序员感到恐惧:在C ++中,将功能添加到对象的最面向对象的方法是通过非成员非友元函数,而不是成员函数(即类方法),因为:
在C ++中,类的接口既是其成员函数,也是同一命名空间中的非成员函数
非友元非成员函数无权访问类内部。因此,使用成员函数而不是非成员非友元函数将削弱类的封装性。
即使是经验丰富的开发人员也会感到惊讶。
(来源:包括Herb Sutter的在线Guru of the Week#84:http://www.gotw.ca/gotw/084.htm)
我认为比较隐蔽的一种编程语言特性是命名空间别名。在我的学校生涯中从未听到过这方面的内容,直到我在boost文档中遇到了相关示例才引起了我的注意。当然,现在我知道了这个特性,你可以在任何标准的C++参考资料中找到它。
namespace fs = boost::filesystem;
fs::path myPath( strPath, fs::native );
using
,我猜这会很有用。 - Siqi Lin在 for
循环的初始化部分不仅可以声明变量,还可以声明类和函数。
for(struct { int a; float b; } loop = { 1, 2 }; ...; ...) {
...
}
这允许使用不同类型的多个变量。
数组操作符是可结合的。
A[8] 是 *(A + 8) 的同义词。由于加法是可结合的,这可以重写为*(8 + A),它是... 8[A] 的同义词。
你没有说这很有用... :-)
A
的类型根本不重要。例如,如果 A
是一个 char*
,那么这段代码仍然是有效的。 - Konrad Rudolph*(A + 8)
。而 8[A] 的值为 *(8 + A)
。它们是相同的。 - Marlon有一件不太为人知的事情是,union 也可以作为模板:
template<typename From, typename To>
union union_cast {
From from;
To to;
union_cast(From from)
:from(from) { }
To getTo() const { return to; }
};
它们也可以拥有构造函数和成员函数。只是不能涉及继承(包括虚函数)。
From
和 To
设置并相应使用,则会触发未定义行为。但是,这样的 union 可以通过特定方式(使用 To
作为无符号字符数组或共享与 From
相同初始序列的结构体)来实现定义良好的行为。即使以未定义的方式使用它,它仍可能对低级别工作有用。无论如何,这只是一个联合模板的示例 - 对于联合模板可能还有其他用途。 - Johannes Schaub - litb*(B *)&a
- Nick BedfordC++是一个标准,不应该有任何隐藏功能...
C++是一种多范式语言,你可以打赌最后的钱里面有隐藏功能。其中一个例子是模板元编程。标准委员会中没有人打算在编译时执行一个图灵完备的子语言。
另一个在C语言中不起作用的隐藏功能是一元+
运算符的功能。您可以使用它来提升和降低各种事物。
+AnEnumeratorValue
现在你的枚举值已经具有完美的整数类型,可以容纳其值。手动操作时,你几乎不会知道该类型!例如,当你想为枚举实现重载运算符时,就需要这样做。
你必须使用一个类,该类使用内部静态初始化程序而没有外部定义,但有时链接失败?该运算符可以帮助创建一个临时变量,而不对其类型进行任何假设或依赖。
struct Foo {
static int const value = 42;
};
// This does something interesting...
template<typename T>
void f(T const&);
int main() {
// fails to link - tries to get the address of "Foo::value"!
f(Foo::value);
// works - pass a temporary value
f(+Foo::value);
}
您想将两个指针传递给函数,但它却无法工作?运算符可能会有所帮助。
// This does something interesting...
template<typename T>
void f(T const& a, T const& b);
int main() {
int a[2];
int b[3];
f(a, b); // won't work! different values for "T"!
f(+a, +b); // works! T is "int*" both time
}