c++的一些资料:
https://cpp.zeef.com/faraz.fallahi
语言核心
一、long long 类型
int 型最大只能表示21亿多的大小,是不是经常感觉不够用?那么 long long 也许能满足你的需求,LINUX平台下它最大可以表示 9223372036854775807。这里简单提一下获取各个数值类型的方法(不同平台下得出结果可能会不同):
#include <limits.h>
#include <iostream>
int main()
{
std::cout<<CHAR_MIN<<std::endl;
std::cout<<CHAR_MAX<<std::endl;
std::cout<<SHRT_MIN<<std::endl;
std::cout<<SHRT_MAX<<std::endl;
std::cout<<INT_MIN<<std::endl;
std::cout<<INT_MAX<<std::endl;
std::cout<<LLONG_MIN<<std::endl;
std::cout<<LLONG_MAX<<std::endl;
std::cout<<UCHAR_MAX<<std::endl;
std::cout<<USHRT_MAX<<std::endl;
std::cout<<UINT_MAX<<std::endl;
std::cout<<ULLONG_MAX<<std::endl;
}
我们看到这里引入的头文件实质上是C语言的头文件,LINUX下可能为 /usr/include/limits.h ,这是因为 C 语言早前就已经包含了 long long 类型了,当然你也可以引入c++的头文件 #include <climits> 来达成相同的效果。
二、列表初始化
int array[] = {1,2,3,4,5};
c++可以像上面那样通过花括号的形式给数组初始化,但是却不能用同样的方式给 vector 初始化。在 c++11 中,这一点得到改善,且可以使用花括号的一致风格为变量或对象进行初始化。
#include <vector>
class User
{
public:
User(std::string _name):name(_name){}
std::string name;
};
int main()
{
std::vector<int> vect = {1,2,3,4,5};
User my = {"yugd"};
}
三、nullptr
设置空指针有三种方法,置为 0 或 NULL(预处理变量,实质上还是0) 或 nullptr。
因为 0 存在多义性,比如经典的分别使用指针和数值型重载的函数,当传入0时,就会出现二义性,此时为明确调用指针型的重载,最好传入 (void*)0 ,如果要明确调用INT型的重载,最好传入 int(0)。(如 jsoncpp 库中 Value.h 文件中的 Value &operator[]( const char *key ); 和 Value &operator[]( UInt index ); ) 所以使用 nullptr 会更清晰直观。
四、enum class
从字面上可以叫 "枚举类" ,俗称 "强类型枚举" ,英文一般叫 "scoped enums" ,它弥补了一些旧式枚举带来的问题:
1、旧式枚举可以隐式转换成 int,意味着枚举与 int 值、枚举与枚举之间可以进行比较(而这通常是不合理的)。强类型枚举则需要强制转换成 int 型,增加了类型安全。
2、旧式枚举因为没有 "界限" 的概念,通过枚举字段直接访问,所以不同枚举不能定义相同名字的枚举字段。在一个大型项目中,这是个比较蛋疼的事。比如这样编译时会报 SUCCESS 重定义:
enum Buy { SUCCESS, MONEY_NOT_ENOUGH, }; enum Sell { SUCCESS, FAILD, };
此时可以使用这样的方法避免该问题:
#include <iostream> struct Buy { enum { SUCCESS = 1001, MONEY_NOT_ENOUGH = 1002, }; }; struct Sell { enum { SUCCESS = 2001, FAILD = 2002, }; }; int main() { std::cout<<Buy::SUCCESS<<std::endl; std::cout<<Sell::SUCCESS<<std::endl; }
但更好的方法是直接使用 enum class。
3、enum class 可以为枚举元素指定类型,如果不指定则默认是 int(但依然不能直接隐式转化成 int),如:
enum class Buy : unsigned int { SUCCESS, MONEY_NOT_ENOUGH, };
此特性使得编译器可以确定枚举参数所占空间的大小,这样 enum class 就可以像普通类一样进行前向声明了,这一点是旧式枚举无法做到的,此特性对于优化大项目的编译时间可能会非常有用。
五、override 与 final
新增的继承控制关键字,override 用于修饰子类的成员方法,明确表示此方法重载了基类的相应方法,编译器会检查函数签名是否完全一致,若不一致将报错。可以避免在想要重载时因签名不匹配,导致事实上并非重载的情况。
final 关键字有两个作用,一是修饰类,禁止该类被继承;二是修饰虚函数(此前只要基类中某成员函数为virtual,则子类重载的函数也自动为virtual函数,即使不用 virtual 修饰,所以只要愿意可以无限重载下去),禁止该虚函数被子类重载。
运行期表现强化:
1、右值引用
构造期表现强化:
可用性强化:
功能强化:
库的变更
一、std::function、std::bind 与 Lambda
std::function 类似于函数指针,但更为灵活,与之相关的是 std::bind 和 Lambda表达式,这两者返回的都是 std::function 对象,三者联系紧密,示例如下:
#include <iostream> #include <string> #include <functional> int add(int i, int j) { return i + j; } int sub(int i, int j) { return i - j; } int main() { //typedef std::function<int(int,int)> Func; //定义一个该函数对象的类型 //Func func; //定义一个该类型的函数对象 std::function<int(int,int)> func; //直接定义一个函数对象 func = add; std::cout<<func(4,3)<<std::endl; //7 func = sub; std::cout<<func(4,3)<<std::endl; //1 //std::bind 返回的就是 std::function 对象,std::bind 中有几个占位符,返回的std::function 函数对象就有几个参数 std::function<int(int)> func1 = std::bind(sub,4,3); std::cout<<func1(5)<<std::endl; //1 // std::function 函数对象可以多出无用参数 std::function<int(int)> func1_ = std::bind(sub,4,3); std::cout<<func1_(5)<<std::endl; //1 //这一点应用很多,如cocos2d-x中使用std::bind来绑定点击处理函数,应该是传入 std::function<void(Ref*)> ,但实际可以这样写:btn->addClickEventListener(std::bind(&GameLayer::backScene, this)); std::function<int(int)> func2 = std::bind(sub,4,std::placeholders::_1); //sub函数的第二个参数被占位为1号参数 std::cout<<func2(3)<<std::endl; //1 std::function<int(int,int)> func3 = std::bind(sub,std::placeholders::_2,std::placeholders::_1); //sub函数第一个参数被占位为2号参数,第二个参数 被占位为1号参数,所以下面的输出不是 1 而是 -1 std::cout<<func3(4,3)<<std::endl; //-1 //Lambda表达式与 std::bind 一样返回的是 std::function 函数对象 std::function<int(int,int)> func4 = [](int i, int j){return i+j;}; std::cout<<func4(4,3)<<std::endl; }