1.类型推导 auto
以前我们类型声明总是要明确的指出所定义的变量类型,但是有的类型就比较冗长,比如 :std::map<int, std::string>::const_iterator itr = m.find(1);
前面的类型又长又不好写
所以我们现在可以使用auto来替代类型,而编译器会自己推导出该变量的类型。
int main()
{
auto i = 10;
auto j = 10.2;
auto k = 3.2f;
auto c = 'c';
auto* p = &i;
return 0;
}
比如这样,尽管我们没有写出i,j,k,c与p是什么类型,但是编译器会通过他初始化的值来推导出他们相应的类型。
在vs2015中我们可以将鼠标悬停在变量上就可以知道他是什么类型。
2.foreach循环
以前我们定义了一个vector容易或者数组的话,我们要变量的时候是定义一个下标,然后通过下标或者指针来遍历,这样我们总是要定义不比要的变量,而且代码也不简洁,现在我们可以这样。
int main()
{
vector<int> v;
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(8);
v.push_back(9);
for (int value : v)
{
cout << value << endl;
}
return 0;
}
原理是对v中的每一个元素进行遍历,然后将元素赋给value,然后通过输出value来将v的每一个元素输出。
3.using代替typedef
在C/C++中,我们经常通过typedef来定义类型的别名,比如我们可以把unsigned int用typedef改为UINT,typedef unsigned int UINT;
这时候我们使用UINT就相当于是在使用unsigned int。
但我们现在有一个更加直观的写法,就是使用using ,using UINT=unsigned int;
这样我们可以很清晰的看出来UINT就相当于是unsigned int。
4.空指针nullptr
在以前我们定义指针的时候,我们会在指针还未有明确的指向时对其赋空也就是
int* p=NULL,但是NULL是一个宏定义。
我们可以看见NULL的本质是0,类型为int,但是我们并不希望这样,我们想要一个专门的指针类型的值来表示指针为空,所以就有了nullptr,以后我们就可以写int* p=nullptr。nullptr就是一个专门用来表示指针空的值。
5.强类型枚举 enum class
例:
enum Direction {
Left, Right
};
enum Answer {
Right, Wrong
};
这个枚举类型中都有一个叫Right的值,但是他们俩所表示的含义却不相同,第一个Right表示的是方向右,第二个Right表示的是正确,并且他们俩的值也是不同地,第一个为1,第二个为0。
这样的话我们在使用的时候就会产生问题,到底我们的Right是表示的方向呢还是正确呢,这时候就说不清了。
所以我们有了强类型枚举,其实就是将枚举类型写在类里。
enum class Direction {
Left, Right
};
enum class Answer {
Right, Wrong
};
auto a = Direction::Left;
auto b = Answer::Right;
if (a == b)
std::cout << "a == b" << std::endl;
else
std::cout << "a != b" << std::endl;
这样子我们就可以很清楚的看出来想要用的Right究竟是哪一个。
6.构造函数的相互调用
例:
class A
{
private:
int x;
int y;
std::string name;
public:
A(int x,int y,string& name)
:x(x),y(y),name(name)
{}
A(int x,int y)
:A(x,y,"A")
{}
A()
:A(0,0)
{}
};
通过上面的例子我们可以看到,当类A构造一个无参对象时会调用无参构造函数,这时在其初始化列表里会调用一次双参构造函数,并且传了两个默认值上去,然后双参构造函数在初始化列表里调用了三参构造函数,并且加了一个默认值,这时候三参构造函数就会完成所有任务,成功定义出一个类对象。
7.禁止重写 final
例:
class A {
public:
virtual void f1() final {}
};
class B : public A {
virtual void f1() {}
};
这时候代码会报错,提示不能重写f1。
8.显式声明重写 override
例:
class A {
public:
virtual void f1() const {}
};
class B : public A {
virtual void f1() {}
};
/*上面的代码在重写函数f1时不小心漏了const,但是编译器不会报错。因为它不知道你是要重写f1,而认为你是定义了一个新的函数。这样的情况也发生在基类的函数签名变化时,子类如果没有全部统一改过来,编译器也不能发现问题。
C++ 11引入了override声明,使重写更安全。*/
class B : public A {
virtual void f1() override {}
};
此时编译报错,提示找不到重写的函数。
class B : public A {
virtual void f1()const override {}
};
这时候就对了。