func预定义标识符
func预定义表示符的基本功能是返回所在函数的名字
#include<string>
#include<iostream>
using namespace std;
const char* hello(){return __func__;}
int main(){
cout<<hello()<<endl;
}
编译器会默认隐式地在函数的定义后定义func标识符;实际代码相当于如下:
const char* hello(){
static const char* __func__="hello";
return __func__;
}
_Pragrma
#pragrma
是预处理指令,可以向编译器传达语言标准之外的信息。
例如#pragrma once指示编译器该头文件应该只能编译一次。
在C++11中,定义了和#pragrma相同功能的操作符_Pragrma
使用方式为_Pragrma(字符串常量);
例如_Pragrma("once");
好处是可以用在宏中展开!
#define CONCAT(x) PRAMGA(concat on #x)
#define PRAGMA(x) _Pragma(#x)
CONCAT(..\concat.dir)
变长参数宏定义以及VA_ARGS
C99标准中可以使用变长参数宏定义,即宏定义中参数列表最后一个参数为省略号。
#define PR(...) printf(__VA_VARGS__)
__VA_VARGS__
可以在宏定义的实现部分替换省略号代表的字符串
宏__cplusplus
why need it
在C和C++混合编写的代码中,常常看到如下的代码
#ifdef __cplusplus
extern "C"{
#endif
//....
#ifdef __cplusplus
}
#endif
- 因为C++编译器会对函数名称进行重整,所以对于C的函数不是很好支持
-
检测版本
__cplusplus宏可以表示该文件用C++来编写,实际上在C++11中,此宏并非只有被定义了和未被定义两种状态,还表示一个整型值,整型值表示当前C++的版本
#if __cplusplus < 201103L
#error "should use C++11 implementation
#endif
静态断言
断言是什么?
断言是将一个返回值总是真的判别式放在语句中,用于排除在设计逻辑上不应该发生的情况
通常而言,断言只是用于调试程序。但是断言仅仅实在程序运行时才能起效,我们希望在编译时做出一些断言。静态断言
因此C++11引入了静态断言static_assert,即可以在编译时期进行检测的断言 :::warning
static_assert(a,"b");
- 参数a:断言表达式,返回一个bool值
- 参数b:一个警告信息,即一个字符串
:::
static_assert是在编译时进行的,因此使用范围比assert更广一点。
noexcept修饰符和操作符
有时候我不希望抛出异常,比如copy操作中,析构函数中,一旦抛出异常,可能会导致内存泄漏等安全问题的发生。
C++11中表示函数不会抛出异常的声明由noexcept修饰,如果noexcept修饰的函数抛出了异常,编译器可以选择直接调用std::terminate()函数来终止程序的运行,比throw要高效一些两种使用形式
void excpt_func() noexcept;
void excpt_func() noexcept (常量表达式);
常量表达式会被转换成bool类型,如果值为true,则表示不会抛出异常,反之则可能抛出,不带参数的修饰表示不会抛出异常。不抛出异常的情况
对于delete来讲,默认是设置成noexcept的
对于析构函数而言,默认是设置成noexcept的,除非显示声明了。
非静态成员的sizeof
sizeof是一个C中遗留下来的运算符,和加减乘除一样。C++98中对于非静态成员变量使用sizeof不能通过编译,但是C++11支持了这一点。
struct People{
public:
int hand;
static People* all;
}
int main(){
People p;
cout<<sizeof(p.hand)<<endl;
cout<<sizeof(People::all)<<endl;
cout<<sizeof(People::hand)<<endl;//only C++11
}
C++98中只有静态成员,或者对象的实例才能对其成员进行sizeof操作。
final/override控制
重载 overload
如果A中的虚函数func被其派生类B再次定义了,那么称B重载了A的函数func
final
有时候我们不希望某个函数被重载,因此在派生类中可以将他声明为final
struct Object{
virtual void fun()=0;
}
struct Base:public Object{
void func() final;//不允许再重载了
}
struct Derived:public Base{
void func(); //无法通过编译,因为final修饰的函数不允许被重载
}
override
如果某个虚函数必须被重载,但是出于种种原因(如拼写错误,函数参数错误等),可能实际在派生类中并未重载,这会导致错误。
C++11提供override描述符,表示该函数必须重载基类中同名的函数,否则无法通过编译
struct Base{
virtual void Turing()=0;
virtual void VNeumann(int g)=0
}
struct Derived :public Base{
void Turning() override; //ok!
void VNeumann(double g) override;//非重载,无法通过编译
}
模板函数的默认参数
在C++98中可以允许模板类由默认的模板参数,其功能类似于函数的默认形参,但是模板函数在C++98中并不允许这一点。
template<typename T=int>
class Defclass{};
template<typename T=int>
void DefTempParm(){};//C++11通过,C++98失败
- 对于类模板来说,对多个参数指定默认值时需要从右往左
- 对于函数模板而言不需要这一点。
模板函数的默认形参不是模板参数推导的依据,函数模板参数的选择总是由函数的实参推导而来的