C++其实有许多的新奇或者冷用法,经过本人整理,给大家普及一下
1.位域结构体
结构体里的成员竟然有个冒号,例如下面的节选代码:
struct BitField
{
unsigned int a:4; //占用4个二进制位;
unsigned int :0; //空位域,自动置0;
unsigned int b:4; //占用4个二进制位,从下一个存储单元开始存放;
unsigned int c:4; //占用4个二进制位;
unsigned int d:5; //占用5个二进制位,剩余的4个bit不够存储4个bit的数据,从下一个存储单元开始存放;
unsigned int :0; //空位域,自动置0;
unsigned int e:4; //占用4个二进制位,从这个存储单元开始存放;
};
位域可以设置成员的二进制位置,对于节省内存是特别好的。
具体用法可以去网上进一步了解。
2.反斜线可以实现多行宏/注释
这个很多人都知道,宏或注释的最后加一个反斜线\,可以多续一行:
#define exitif(cond) do{\
if(cond)\
exit(0); \
}while(0)
//注意:反斜线必须是最后一个字符\
才行;\
最后一行不用加
3.标识符中可以使用$
这个当做冷知识吧,不要多用,毕竟兼容性不是很好。
int var$1 = 5;
int $var1=5;
int var1$ = 5;
cout<<var$1<<endl;
cout<<$var1<<endl;
cout<<var1$<<endl;
有些编译器还不支持。
4.lambda表达式(C++11)
lambda表达式又称匿名函数,可以直接当成函数变量使用。
可以使用auto来存储它。
例如:
auto func = [](int a) -> int { return a*a; }
cout<<"5*5="<<func(5)<<endl;
语法形式:
[函数对象参数可以为空] (函数参数) mutable 或 exception 声明可以不加 -> 返回值类型可以不加 { 函数体若无return则自动判定为void函数 }
看下面几个例子就懂了:
[] (int x) {return x*x;}
[] (int& a) { return ++a; }
[] { g_score++; } //无参数时小括号可以省略
至于中括号内、mutable等的用法可以取网上查都有的。
另外,C++14还支持泛型lambda,参数类型可以是auto!
5.__noop
这个类似关键字的东西的作用是,可以当成一个接受任何类型任何个数参数的函数名,而且什么也不干。它和下面这个一个道理:
void UselessFunction(...)
{}
可以用于调试:
#ifdef DEBUG
#define PRINT printf
#else //不调试的时候不输出
#define PRINT __noop
#endif
注意是两个下划线.
6.#include_next
这个是GNU扩展,有些编译器不能用的
它的作用是,找第二个符合名字目录及子目录下的头文件。
尽量不要用,除非真的不太行
可以参考
https://blog.csdn.net/qq_17291647/article/details/103572863
7.新的强制转换
C++为了分类强制转换,新添四个强制转换关键字,分别是static_cast、dynamic_cast、const_cast和reinterpret_cast。
它们的作用如下:
参考 https://www.cnblogs.com/chenyangchun/p/6795923.html
关键字 | 安全性 | 作用 |
---|---|---|
static_cast | 高 | ①普通类型转换 ②基类子类指针/引用转换(最好向上)③void* 转成type* ④type 转成const type |
dynamic_cast | 较高 | 基类子类的上下转换(可以向下,更为安全) |
const_cast | 较高 | 去掉const!! (指针也可) |
reinterpret_cast | 极低 | 仅仅是二进制操作,把指针转成数字。。! |
8.新的for循环(C++11)
这么好用的for循环怎么能错过呢!
std::vector<int> numbers {0,1,2,3};
for(const auto&i : numbers)
std::cout<<i<<" ";
格式:
for(type 元素 : 容器)
{操作}
其中的type:
①只读:auto / const auto& 【std::set只能用只读】
②可改:auto&
std::for_each也是不错的:
std::vector<int> numbers {0,1,2,3};
std::for_each(numbers.begin(),numbers.end(),
[](auto ele) //注意:这是一个lambda表达式
{
std::cout<<ele<<" ";
}
);
9.“双非” (!!)
这个操作并非多此一举(其实还是没用)
它的用途就是把int转成bool.(更加标准。。)
库函数竟然也用到了:
//from assert.h ---↓line64
#ifdef NDEBUG
#define assert(_Expression) ((void)0)
#else /* !defined (NDEBUG) */
#if defined(_UNICODE) || defined(UNICODE)
#define assert(_Expression) \
(void) \
((!!(_Expression)) || /*←这里*/\
(_wassert(_CRT_WIDE(#_Expression),_CRT_WIDE(__FILE__),__LINE__),0))
#else /* not unicode */
#define assert(_Expression) \
(void) \
((!!(_Expression)) || /*←这里*/\
(_assert(#_Expression,__FILE__,__LINE__),0))
#endif /* _UNICODE||UNICODE */
#endif /* !defined (NDEBUG) */
说明编写者也想到了这个奇葩用法。
10.获取变量的类型名称字符串
用到的关键字 (这是一个受头文件限制的操作符) 是typeid.
注意: 需要包含头文件< typeinfo > ,否则编译器会找上门来:
[Error] must #include < typeinfo > before using typeid
示例:
int a=1;
double f=6.0;
string s="Rico";
cout<<"type of a:"<<typeid(a).name()<<endl;
cout<<"type of f:"<<typeid(f).name()<<endl;
cout<<"type of s:"<<typeid(s).name()<<endl;
输出竟然不太好:
type of a:i
type of f:d
type of s:Ss
说明这种方法确实有用,但不是很稳定——能少用就少用。
真的要用的话只能特判:
if(typeid(a)==typeid(int)) //准行
cout<<"int";
【未完待续】