❀C++11(基础篇)
# 结构体初始化
struct A
{
int a;
int b;
};
A w = {1, 2};
A z{1, 2}; //等号可省
//这个语法可以用来对 new空间的初始化
int *p = new int[5]{1,2,3};
A *pa = new A [2]{{1,1}, {2,2}}; // 这里需要提供构造函数
2
3
4
5
6
7
8
9
10
11
12
# initializer_list
对于多参数的构造,c++在 vector、list中提供了一个initializer_list的构造函数
initializer_list<int> it = {1,2, 3,4,5,6,7};
# decltype
获取一个变量的类型,再用来定义另一个变量
int x = 1;
decltype(x) a = 1;
map<sting, string> dict;
auto it = dict.begin();
vector<decltype(it)> v;
2
3
4
5
6
# nullptr
#define NULL ((void*)0)
# C++ 11 STL
- 新增容器
- 增加已有容器的一些特性
int a[10];
array<int, 10> a2; // 可以实现越界的检查
2
forward_list
# default 和 delete
class A
{
A() = default;
A(int a = 1) //若自定义了构造函数或者拷贝构造,编译器是无法生成构造的,若要求编译器生成使用 default
{}
};
class A
{
A(const A&a) = delete; //类内部也无法拷贝
private:
A(const A&a); //只声明不实现;且声明成私有—— 对象无法被拷贝
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 特殊类-单例模式
类的构造函数是私有的——可以保证对象只能在堆上创建
class HeapOnly
{
public:
static HeapOnly* CreateObj()
{
return new HeapOnly;
}
private:
HeapOnly()
{}
HeapOnly(const HeapOnly& );//只声明不实现,实现无实际意义——防拷贝
//HeapOnly(const HeapOnly& ) = delete; C++11 可以这样,无论public还是private都可以
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 只能在栈上创建对象
class StackOnly
{
public:
StackOnly() {}
private:
void* operator new(size_t size);
void operator delete(void* p);
};
//缺陷:没有禁掉在静态区的对象
2
3
4
5
6
7
8
9
10
- 不能被继承的类
1、将构造函数私有,子类继承后无法实例化对象
2、加final,更彻底
class A final
{
// ....
};
2
3
4
- 设计一个例,只能创建一个对象(单例模式)——保证全局只有唯一一个实例对象
1、将构造函数私有,拷贝构造和赋值防拷贝
条件编译解决线程安全问题
#ifdef __WIN32
//win 多线程api
#else
//linux pthread
#endif
2
3
4
5
C++11在语言层对其进行了封装
单例模式可以不考虑释放,
# 其他
自动推导类型
initializer_list
auto i = 1;
decltype(i) p;
2
decltype 不能作返回值,但可以用来指定函数返回类型
template<class T1, class T2>
auto F(T1 t1, T2 t2) -> decltype(t1 * t2)
{
decltype(t1 * t2)ret;
return ret;
}
2
3
4
5
6
- array 和 a[]
意义:array对越界检查
array<int , 9> a1;
a1.at(11);
2
0.25
# 右值引用和移动语义
左值 : 可以取地址+对它赋值(特殊情况:const -- 可以取地址,但不能赋值,仍是左值)
左值引用:给左值取别名
右值:不能取地址 + 不能修改(不能出现在 = 的左边)——常量、表达式返回值、传值返回函数的返回值(这个不能是左值引用的返回)。对临时对象的右值引用,会将临时对象的空间利用起来而不进行销毁——资源转移。
右值引用:给右值取别名
右值引用后,会开一个空间将右值存储起来
int && rr1 = 10;
//const int && rr1 = 10;
rr1 = 20;
2
3
4
5
右值引用只能引用右值,不能引用左值。但右值引用可以引用move后的左值
int a = 10;
int&& r3 = std::move(a);
2
- 函数返回对象出了函数作用域不存在,就不能用引用返回;传值返回会存在(深)拷贝
——右值引用
//移动构造 将亡值
string(string&& s)
:_str(nullptr)
,_size(0)
,_capacity(0)
{
this->swap(s);
}
//移动赋值
string& operator=(string&& s)
{
this->swap(s);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
浅拷贝实现移动构造没有意义
int main()
{
string s1("111");
//以下都是移动构造,但s1——move后会失效——
lt.push_back("2222");
lt.push_back(string("2222"));
lt.push_back(std::move(s1));
return 0;
}
2
3
4
5
6
7
8
9
10
- 完美转发
在模板里T&& 表示万能引用,既能接受左值也能接受右值;int && 只能接受右值或者move以后的左值
void Fun(int &t) {std::cout << "左值引用" << std::endl;}
void Fun(const int &t) {std::cout << "const 左值引用" << std::endl;}
void Fun(int &&t) {std::cout << "右值引用" << std::endl;}
void Fun(const int &&t) {std::cout << "const右值引用" << std::endl;}
template<typename T>
void PerfectForward(T&& t)
{
// Fun(t); // 无论传什么,只会匹配左值——属性退化成左值
Fun(std::forward<T>(t)); // 保持原来的属性,完美转发
}
int main()
{
int a = 1;
const int b = 1;
PerfectForward(1);
PerfectForward(a);
PerfectForward(b);
PerfectForward(std::move(b));
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- default
若编译器不生成构造函数,可以强制其生成
class person
{
person() = default;
person(const person& p)
:_name(_p._name)
,_age(p._age)
{}
};
2
3
4
5
6
7
8
9
# 可变参数
template<typename ... Types> //模板参数包
void ShowList(Types ... args)
{
cout<< sizeof...(args) << endl;
}
2
3
4
5
取出参数:
void ShowList() // 一个参数时不用推导,直接调用
{
std::cout << std::endl;
}
template<class T>
void PrintArg(T t)
{
cout << t << " ";
}
template<class T , class ... Args>
void ShowList(class T, Args ... args)
{
cout<< sizeof...(args) << endl;
ShowList(args...);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template<class T>
void PrintArg(T t)
{
cout << t << " ";
}
template<class ...Args>
void ShowList(Args... args)
{
int arr[] = { (PrintArg(args), 0)...}; // 逗号表达式,会展开
cout << endl;
}
//(PrintArg(args), 0) -> 0 :数值初始化需要一个值,而PrintArg返回为void,需要用0去替换
//{ (PrintArg(args), 0)...}; = { (PrintArg(args), 0), (PrintArg(args), 0), (PrintArg(args), 0) };
template<class T>
int PrintArg(T t)
{
cout << t << " ";
return 0;
}
template<class ...Args>
void ShowList(Args... args)
{
int arr[] = { PrintArg(args)...}; // 逗号表达式,会展开
cout << endl;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
auto swap = [](&a, &b) {int tmp = a; a = b; b = tmp;};
- 用法一:无敌打印函数
void Print()
{}
template <typename T, typename... Types>
void Print(const T& firstArg, const Types&... args)
{
std::cout << firstArg << std::endl;
Print(args...);
}
Print("hello", 3.14, std::bitset<16>(256));
2
3
4
5
6
7
8
9
10
11
- 用法二:可变参数求最大
int maximum(int n) { return n; }
template<typename... Args>
int maximum(int n, Args... args)
{ return std::max(n, maximum(args...)); }
2
3
4
5
- 用法三:递归继承
template<typename... Values> class tuple;
template<> class tuple<> {};
template<typename Head, typename... Tail>
class tuple<Head, Tail...>
:private tuple<Tail...>
{
typedef tuple<Tail...> inherited;
protected:
Head m_head;
public:
tuple() {}
tuple(Head v, Tail... vtail) :m_head(v), inherited(vtail...) {}
//Head head() {return m_head;}
auto head()->decltype(m_head) {return m_head;}
inherited& tail() {return *this;}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# emplace_back
std::list<std::pair<int, std::string>> lt;
lt.push_back(std::make_pair(10, "hello")); //先使用构造构造临时对象,然后移动构造。
lt.emplace_back(10, "hello"); //直接将结果构造到lt对象
2
3
4
# lambda——定义函数,可以定义在局部
可调用对象:仿函数、函数指针、lambda表达式
auto f1 = [](const Goods& g1, const Goods& g2){return g1.price > g2.price;};
sort(v.begin() , v.end(), f1);
sort(v.begin() , v.end(), MyCompare());
2
3
4
[capture-list] (parameters) mutable-> return-type {statement}
捕捉列表、参数(可省)、 、返回值类型(可省)、函数实现
最简单的lambda表达式:[] {}
[ 捕获 ] ( 形参 ) lambda说明符 约束(可选) { 函数体 }
[var] 传值方式捕捉变量var
[=] 传值方式捕捉所有父作用域的变量(包括this)
[&var] 引用捕捉 var
[&] 引用捕捉所有父作用域的变量(包括this)
int id = 0;
auto f = [id]()mutable{ id++; }; //传值, 不加mutable 不可以改变id
2
# 类型转换
隐式类型条件:
- 相近类型
否则需要强转。
static_cast \ reinterpret_cast \ const_cast \ dynamic_cast
- static_cast:相近类型的转换,规范C的隐式类型转换
double a = 3.14;
int b = static_cast<int> (a);
std::cout << a << std::endl;
std::cout << b << std::endl;
2
3
4
- reinterpret_cast : 可以将变量转换成指针变量。
int a = 0;
int *p = reinterpret_cast<int*> (a);
std::cout << p << std::endl;
2
3
- const_cast:const修饰的变量仍然是在栈上的,可以通过指针修改
//volatile const int s = 1;
const int s = 1;
int* p = const_cast<int*> (&s);
*p = 2;
std::cout << s << "___" << *p << std::endl;
//编译器优化后,导致s没有从内存中取,编译器直接读成一个常数;而实际s的值被修改了
//本质和c语言的int* p = (int*) (&s);是一致的,但增加const_cast可以起到提醒的作用,防止和编译器优化冲突。
2
3
4
5
6
7
8
- dynamic_cast : 只能用于含虚函数的类
用于多态的转换父类对象的指针或引用给子类对象
父 = 子 ——向上转,不需要转换,赋值兼容
子 = 父 ——使用dynamic_cast会安全
B* p = dynamic_cast<B*> (A());
// 如果p指向父类对象,转换不成功返回nullptr
// 子类 返回子类对象的指针
class A {
public:
virtual void f() { std::cout << "class A" << std::endl;}
};
class B:public A {
public:
};
void Fun(A* pa) {
B* pb = dynamic_cast<B*> (pa);
if(pb == nullptr) {
std::cout << "转换失败" << std::endl;
}else {
std::cout << "转换成功" << std::endl;
pb->f();
}
}
A a;
B b;
Fun(&a);
Fun(&b);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# explicit
用在构造函数之前,使得一个类型的参数无法隐式转化成另一个类型。
# 使用别名alias
template <typename T>
using VEC = std::vector<T,AllocatoR<T>>;
VEC<int> v;
//typedef void(*func)(int);
using func = void(*)(int);
//使用
void example(int) {}
func fn = example;
2
3
4
5
6
7
8
9
10
11
# noexcept
void func() noexcept; = void func() noexcept(true);
//保证函数不丢出异常,异常是一定要被处理的,会一直往调用的函数传递直至被处理
Myvector(Myvector&& str) noexcept //在包含移动构造移动赋值的语句后,指定不抛出异常,保证使用者大胆使用
{}
2
3
4
5
# override
保证虚函数一定可以被重新。
# final
- struct Myclass final{}; 类不能被继承
- virtual void f() final; 虚函数不能被重写