C++11常用关键字
一、using的使用
c++中using用于声明命名空间,声明命名空间后,可以直接使用命名空间中定义的类。
在c++11中赋予了using新的功能:
- 定义别名: 类型别名和类型名字等价,typedef和using定义的别名在语义上等效。using的可读性更好。
- 定义模版别名:使用using给模版指定别名更灵活。
#include <iostream>
#include <memory>
#include <string>
#include <map>
//声明命名空间
using namespace std;
template<typename T>
struct MapType
{
typedef map<int, T> type;
};
template <typename T>
using mymap = map<int, T>;
int main(int argc, char *argv[])
{
//typedef 定义别名
typedef unsigned int uint_t;
//using 定义别名
using uint_t1 = unsigned int;
uint_t1 a = 1;
cout <<"a = "<< a << endl;
//typedef 模版类定义别名
MapType<int>::type mType;
mType.insert(make_pair(1, 2));
mType.insert(make_pair(3, 4));
cout << "mType[1] = " << mType[1] << endl;
//using 模版类定义别名
mymap<int> m;
m.insert(make_pair(1, 2));
m.insert(make_pair(3, 4));
cout << "m[1] = " << m[1] << endl;
mymap<string> m1;
m1.insert(make_pair(1, "hello"));
m1.insert(make_pair(2, "world"));
cout << "m1[1] = " << m1[1] << endl;
return 0;
}
二、final和override
- c++中增加final关键字
限制某个类不能被继承或某个函数不能被重写,如果使用final关键字修饰函数,只能修饰虚函数,并且要把final关键字写在类或者函数的后面。 - override关键字确保派生类中声明的重写函数与基类中的虚函数有相同的名字,保证重写函数的正确性,提高了代码的可读性,与final关键字一样,要写在函数后面。
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class Base
{
virtual void test()
{
cout << "Base test" << endl;
}
virtual void test1()
{
cout << "Base test1" << endl;
}
};
//final修饰类,限制类不能被继承
class Child final: public Base
{
//final修饰函数,限制虚函数不能被重写
void test() final
{
cout << "Child test" << endl;
}
//如果重写的函数名与基类的虚函数不同,语法错误
void test1() override
{
cout << "Child test1" << endl;
}
};
/**
//继承,语法错误
class GrandChild : public Child
{
//重写,语法错误
//void test(){}
};
*/
int main(int argc, char *argv[])
{
return 0;
}
三、noexcept
c++98提供了一套完善的异常处理机制:
在函数后面添加异常接口声明throw(),其参数是可以抛出的异常类型
如果没有添加异常接口声明,可以抛出任意异常类型。
#include <iostream>
#include <string>
using namespace std;
struct MyException
{
MyException(string _msg):msg(_msg){}
string msg;
};
double division(int a, int b) throw(MyException)
{
if (b == 0) {
cout<<"division is zero."<<endl;
throw MyException("division is zero.");
}
return a*1.0/b;
}
int main(int argc, char *argv[]) {
try {
division(10, 0);
}catch(MyException e) {
//这里会运行
//double division(int a, int b) 没有添加异常接口声明,可以抛出任意类型
//double division(int a, int b) throw(MyException) 参数表示可以抛出的异常类型
//这里不会运行
//double division(int a, int b) throw() 参数列表为空,表示不允许抛出异常
cout<<"catch : " <<e.msg<<endl;
}
}
在c++11中,不会抛出异常的动态异常声明被noexcept取代,表示其修饰的函数不会抛出异常,不过如果被noexcept修饰的函数抛出异常,编译器可以直接调用std::terminate()函数终止程序运行,这比基于异常机制的throw的效率高。
struct MyException
{
MyException(string _msg):msg(_msg){}
string msg;
};
double division(int a, int b) noexcept
{
if (b == 0) {
cout<<"division is zero."<<endl;
throw MyException("division is zero.");
}
return a*1.0/b;
}
int main(int argc, char *argv[]) {
try {
division(10, 0);
}catch(MyException e) {
//不会运行
cout<<"catch : " <<e.msg<<endl;
}
}
四、静态断言static_assert
五、原始字面量
六、空指针类型nullptr
在c++中,为提高程序的健壮性,一般会在定义指针的时候完成初始化,在指针指向未明确的情况下,都会给指针初始化为NULL,避免产生野指针。
c++中将NULL定义为字面常量0,从而造成在函数重载时,NULL和0无法区分。
c++11引入新的关键字nullptr,nullptr专门用于初始化空类型指针,nullptr可以隐式转化为不同类型的指针,可以完美解决重载问题。
void fun(char *p)
{
cout<<"fun char*"<<endl;
}
void fun(int p)
{
cout<<"fun int "<<p<<endl;
}
int main(int argc, char *argv[])
{
//fun(NULL); //语法错误,存在二义性,NULL既是一个整数,也是一个指针
fun(nullptr);
fun(1);
}
七、常量表达式修饰符:constexpr
c++11之前只有const关键字,从功能上说,它有双重语义:变量只读,修饰常量。
c++11引入新的关键字,constexpr,这个关键字可以修饰常量表达式,所谓常量表达式:由>=1个常量组成并在编译过程得到计算结果的表达式。
常量表达式和非常量表达式的计算时机不同,非常量表达式是在程序的运行阶段得到运算结果,常量表达式在程序的编译阶段得到运算结果,极大提高程序的计算效率。
通常建议将const和constexpr的功能区分,表达“只读”语义用const, 表达“常量”语义用constexpr。在表达常量语义时,const和constexpr等价,都在程序的编译阶段得到运算结果。
我们还可以用constexpr修饰函数返回值,这些函数被称作常量表达式函数,包括:
- 普通函数/类成员函数
- 模版函数
- 类构造函数
#include <iostream>
#include <string>
using namespace std;
struct Test
{
//修饰构造函数,得到一个常量构造函数,函数体必须为空,并且用初始化列表的方式为成员变量赋值
constexpr Test(int _id, int _num):id(_id), num(_num)
{}
int id;
int num;
};
//修饰函数,需满足1、必须有返回值;2、不能出现非常量表达式之外的语句
constexpr int fun()
{
constexpr int res = 2;
/**
for (int i=0;i<res;i++)
{
cout<<"hello"<<endl;
}
**/
return res;
}
//修饰模版函数,如果实例化的结果不满足常量表达式函数的要求,constexpr会自动忽略,函数等同于一个普通函数
template <typename T>
constexpr T display(T t)
{
return t;
}
int main(int argc, char *argv[])
{
constexpr Test t{1, 2};
const Test b{2,3};
cout<<fun()<<endl;
//1是常量,符合常量表达式函数要求,constexpr有效
cout<<display(1)<<endl;
int val = 3;
//val是变量,不符合常量表达式函数要求,constexpr无效
cout<<display(val)<<endl;
//t是常量,符合常量表达式函数要求,constexpr有效
cout<<display(t).id<<endl;
constexpr Test t2(3, 3);
}
八、默认函数控制:=default 和 =delete
在c++11中,用 =default修饰的是函数是显式默认缺省函数,用=delete修饰的是显式删除函数。
- =default的优势
因为用户定义的函数没有编译器自定义的默认函数执行效率高,所以c++引入了=default修饰符。
不能使用=default修饰下述六个函数以外的函数,使用=default修饰的函数和c++提供的默认函数是等价的。
默认函数除了可以在类的内部指定,也可以在类的外部指定。
- =delete的优势
=delete可以避免用户使用一些不应该使用的类的成员函数,这种方式可以防止某些类型之间进行自动隐式类型转换产生的错误。
#include <iostream>
#include <string>
using namespace std;
class Base
{
public:
//无参构造函数
Base() = default;
//拷贝构造函数
Base(const Base& b) = default;
//移动构造函数
Base(Base&& b) = default;
//复制赋值操作符重载函数
Base& operator=(const Base& b) = default;
//移动赋值操作符重载函数
Base& operator=(Base&& b) = default;
//析构函数
~Base();
void fun(int a) {
cout<<"a="<<a<<endl;
}
void fun(double a) = delete;
};
//default 函数可以在类体外定义(out-of-line),也可以在类体内定义(inline)
Base::~Base() = default;
int main(int argc, char *argv[])
{
Base base;
base.fun(1);
//语法错误
//base.fun(1.0);
}
3074

被折叠的 条评论
为什么被折叠?



