我发现大多数来自 Scott Meyers 的“ 有效的 C + + ”类型的书或者 Herb Sutter 的“ 卓越的 C + + ”类型的书都很容易阅读,并且在 C + + 的已知和不太为人所知的特性方面有着相当丰富的信息。
我最喜欢的是一个能让任何 Java 程序员毛骨悚然的东西: 在 C + + 中,the most object-oriented way to add a feature to an object is through a non-member non-friend function, instead of a member-function(即类方法) ,因为:
If two different types are present before and after the : in the ternary (?:) operator expression, then the resulting type of the expression is the one that is the most general of the two. For example:
void foo (int) {}
void foo (double) {}
struct X {
X (double d = 0.0) {}
};
void foo (X) {}
int main(void) {
int i = 1;
foo(i ? 0 : 0.0); // calls foo(double)
X x;
foo(i ? 0.0 : x); // calls foo(X)
}
map::operator[] creates entry if key is missing and returns reference to default-constructed entry value. So you can write:
map<int, string> m;
string& s = m[42]; // no need for map::find()
if (s.empty()) { // assuming we never store empty values in m
s.assign(...);
}
cout << s;
注意,我们还使用了一个
two-argument version of operator
删除而不是通常的删除
一个论点的版本,这个
two-argument version is another
"usual" version of member operator
基类经常使用的删除
期望派生类继承的
它们的操作符删除实现。
第二个参数将包含
物体的大小
deleted—information that is often
有助于实现自定义内存
管理层。
template <typename T>
class Creator {
friend void appear() { // a new function ::appear(), but it doesn't
… // exist until Creator is instantiated
}
};
Creator<void> miracle; // ::appear() is created at this point
Creator<double> oops; // ERROR: ::appear() is created a second time!
Fred* f = new(ram) Fred(); http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10
f->~Fred();
我最喜欢的秘密我很少看到使用:
class A
{
};
struct B
{
A a;
operator A&() { return a; }
};
void func(A a) { }
int main()
{
A a, c;
B b;
a=c;
func(b); //yeah baby
a=b; //gotta love this
}
class Empty {};
namespace std {
// #1 specializing from std namespace is okay under certain circumstances
template<>
void swap<Empty>(Empty&, Empty&) {}
}
/* #2 The following function has no arguments.
There is no 'unknown argument list' as we do
in C.
*/
void my_function() {
cout << "whoa! an error\n"; // #3 using can be scoped, as it is in main below
// and this doesn't affect things outside of that scope
}
int main() {
using namespace std; /* #4 you can use using in function scopes */
cout << sizeof(Empty) << "\n"; /* #5 sizeof(Empty) is never 0 */
/* #6 falling off of main without an explicit return means "return 0;" */
}
The class and struct class-keys are nearly identical. The main difference is that classes default to private access for members and bases, while structs default to public:
// this is completely valid C++:
class A;
struct A { virtual ~A() = 0; };
class B : public A { public: virtual ~B(); };
// means the exact same as:
struct A;
class A { public: virtual ~A() = 0; };
struct B : A { virtual ~B(); };
// you can't even tell the difference from other code whether 'struct'
// or 'class' was used for A and B
namespace {
// Classes, functions, and objects here.
}
Unnamed namespaces behave as if they was replaced by:
namespace __unique_name__ { /* empty body */ }
using namespace __unique_name__;
namespace __unique_name__ {
// original namespace body
}
".. where all occurances of [this unique name] in a translation unit are replaced by the same identifier and this identifier differs from all other identifiers in the entire program." [C++03, 7.3.1.1/1]
struct A {
protected:
int a;
};
struct B : A {
// valid: *can* access protected member
static int get(A &x) { return x.*(&B::a); }
};
struct C : A { };
当然,它也适用于 std::stack示例。
void f(std::stack<int> &s) {
// now, let's decide to mess with that stack!
struct pillager : std::stack<int> {
static std::deque<int> &get(std::stack<int> &s) {
return s.*(pillager::c);
}
};
// haha, now let's inspect the stack's middle elements!
std::deque<int> &d = pillager::get(s);
}
在派生类中使用 using 声明会更容易,它使成员名称为公共的,并引用基类的成员。
void f(std::stack<int> &s) {
// now, let's decide to mess with that stack!
struct pillager : std::stack<int> {
using std::stack<int>::c;
};
// haha, now let's inspect the stack's middle elements!
std::deque<int> &d = s.*(&pillager::c);
}
#include <stdio.h>
struct A { int d; int e() { return d; } };
int main() {
A* a = new A();
a->d = 8;
printf("%d %d\n", a ->* &A::d, (a ->* &A::e)() );
return 0;
}
template<class int>
class foo;
template
class foo<0> {
int* get<0>() { return array; }
int* array;
};
template<class int>
class foo<i> : public foo<i-1> {
int* get<i>() { return array + 1; }
};
I've used that to generate a class with 10-15 functions that return pointers into various parts of an array, since an API I used required one function pointer for each value.
For MSVC they are listed in a 单人间. They could be documented in a single place for the others too, but with the above commands you can clearly 看 what is and isn't defined and exactly what values are used, after applying all of the other command-line switches.
The ternary conditional operator ?: requires its second and third operand to have "agreeable" types (speaking informally). But this requirement has one exception (pun intended): either the second or third operand can be a throw expression (which has type void), regardless of the type of the other operand.
换句话说,可以使用 ?:运算符编写以下完全有效的 C + + 表达式
i = a > b ? a : throw something();
顺便说一句,throw 表达式实际上是 一种表达方式(类型为 void)而不是语句,这是 C + + 语言的另一个鲜为人知的特性。这意味着,除了其他事情之外,下面的代码是完全有效的
struct MyAwesomeAbstractClass
{ ... };
template <typename T>
MyAwesomeAbstractClass*
create_awesome(T param)
{
struct ans : MyAwesomeAbstractClass
{
// Make the implementation depend on T
};
return new ans(...);
}
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);
}
将数组衰减为指针
Do you want to pass two pointers to a function, but it just won't work? The operator may help
// 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
}
struct A { void f() { } };
struct B : virtual A { void f() { cout << "B!"; } };
struct C : virtual A { };
// name-lookup sees B::f and A::f, but B::f dominates over A::f !
struct D : B, C { void g() { f(); } };