这里主要是对C++11比较重要的一些的东西的使用进行讲解和如何去使用。
C++11
// C++11.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <string>
#include <vector>
#include <complex> //复数
#include <set>
using namespace std;
//(2).自动推到函数
double f() { return 1.0; }//定义了函数
auto d = f();//自动推到函数
//1.tuto自动类型的推导
void test01()
{
//1.自动推到基础类型
auto i = 42;//自动推到变量
//3.对复杂类型的推到,迭代器
vector<string>v;
v.push_back("123456");
auto pos = v.begin();
//4.推导lamuda表达式
auto l = [](int x)->bool {
cout << "输入的参数为" << x << endl;
cout << "lamuda表达式" << endl;
return true;
};
{
cout << i << endl;
cout << d << endl;
cout << *pos << endl;//如果容器中的数据为空,引用会报错
cout << l(1) << endl;
}
//注意:类中的成员变量式不能够进行类型推导的,因为类只是声明,初始化才赋值
//类中不能使用auto
}
//2.一致性初始化和初值列
class Test02
{
public:
//一致性初始化,就是使用大括号进行初始化{}
int values[3]{ 1,2,3 };
std::vector<int>v{ 2,3,4,5,8 };
std::vector<std::string>cities{
"Berlin","New York","London","Cairo","Cologne"
};
std::complex<double>c{ 4.0,3.0 };
//初值列,即没有指定的值的变量,自动赋值为0或者nullptr
int i;
int j{};
int* p;
int* q{};
void test() {
cout << "i的值:" << i << endl;
cout << "j的值:" << j << endl;
cout << "p的值:" << p << endl;
cout << "q的值:" << q << endl;
}
//窄化:精度降低或者是数值类型不匹配,对大括号来说都是不可以的
//int x3{ 5.0 };//错误
char c1{ 7 };
//char c2{ 99999 };
std::vector<int>v1{ 1,2,3,4,5 };
//std::vector<int>v2{1,2.3,4,5.6}
//用户的自定义的类型的初值列class template::initializer_list<>
void print(std::initializer_list<int>vals)
{
for (auto p = vals.begin(); p != vals.end(); ++p) {
cout << *p << "\n";
}
}
};
void test02()
{
Test02 test;
test.test();
test.print({ 12,3,5,7,11,13,17 });
}
//3.增加类似for_each()的循环
void test03()
{
//打印集合中的元素
for (int i : {2, 3, 5, 7, 9, 13, 17, 19})
{
cout << i << endl;
}
//容器中每个数乘以3
std::vector<double>vec{ 2.3,5.5,2.6,4.2,3.6 };
for (auto& elem : vec)
{
elem *= 3;
}
}
template<class T>
void printElements(const T& coll)
{
for (const auto& elem : coll)
{
std::cout << elem << std::endl;
}
//等同于
//for (auto pos = coll.begin(); pos != coll.end(); pos++)
//{
// std::cout << elem << std::endl;
//}
}
//4.move搬迁语句,避免非必要的拷贝和临时对象
template<class X>
void createAndInsert(std::set<X>& coll)
{
X x;
coll.insert(x);
coll.insert(std::move(x));
}
//5新式的字符串字面常量Raw String
void test05()
{
//Raw String
string a = "\\\\n";//表示两个反斜线和一个n
string b = R"(\\n)";
//如果要在R中出现括号),使用定义符,16个基本的字符,不可以含有反斜线,空格,和小括号
string c = R"nc(\dfg dfj\fd p90()(000))()())nc";
//编码的字符串,使用不同的编码完成国际化
cout << u8"hello" << endl;//utf8,字符类型是const char
cout << u"hello" << endl;//string literal,类型char16_t的字符
cout << U"hello" << endl;//string literal,类型char32_t的字符
cout << L"hello" << endl;//wide string literal,类型wchar_t的字符
}
//6关键字noexcept,用来指明某个函数无法或不打算抛出异常
void foo() noexcept;
//7关键字constexpr,用来让表达式核定于编译期
constexpr int square(int x)
{
return x * x;
}
void test07()
{
float a[square(9)];
cout << sizeof(a) / sizeof(float) << endl;
}
//9Lambda;语法[](){}(),指定返回值的类型[](参数)->类型 {};(就等于函数里面嵌套函数了)
void test09()
{
[] {cout << "hello lambda" << endl; }();//直接调用
//把他转递给对象
auto l = [] {cout << "hello lambda2" << endl; };
l();
char16_t q='a';//两个字节的char
cout << sizeof(q) << endl;
}
int main()
{
test09();
}
已经分小点测试了,需要学习的直接拿走,自己动手实践一下就能够加深印象和理解的,希望都不要觉得C++难。
拓展:
前几天,写了C++的中简单的使用的一些知识点,也测了好多小的点,今天有空,把没有写完的扩展完成了。
新增:
智能指针,我们都知道,C++的神奇之处就在于指针的使用,如果没有了指针就没有了灵魂了,但是对于初学者来说,指针真的是一个痛点,特别是内存的问题就是难点的问题了,在堆上的内存还是需要我们程序员去释放内存的,如果忘记的释放,那么我们的程序就会崩掉。
智能指针的用处:引入了智能指针,就是可以不用我们再去释放在堆上开辟的空间了。
//智能指针
//需要的头文件#include <memory>
void test10()
{
//智能指针的构造(怎么样去弄一个智能指针出来)
//1.直接使用构造函数
shared_ptr<int>ptr(new int(10));//在堆上开辟了int类型*ptr=10
cout << "指针的地址"<<ptr << endl;//指针的地址
cout <<"指针对应的值"<< *ptr << endl;//指针对应的值
*ptr = 100;//使用指针修改数据
cout << *ptr << endl;
//2.使用make make_shared<int>(100)
shared_ptr<int>ptr1 = make_shared<int>(20);
shared_ptr<int>ptr2{new int(101)};//结合使用C++的{}一致性初始化
cout <<"结合使用C++的{}一致性初始化ptr2的值:"<< *ptr2 << endl;
cout << " ptr1的指针的地址:" << ptr1 << endl;
cout <<"get()返回的指针的地址:"<< ptr1.get() << endl;
cout << " ptr1的值:" << *ptr1 << endl;
cout << " ptr1的值:" << *ptr1.get() << endl;
//3.使用已经存在的指针拷贝
{
shared_ptr<int>ptr3 = ptr2;
cout << "引用计数:" << ptr2.use_count() << endl;//是多个指针指向了同一个内存空间
//ptr2和ptr3指向了同一个空间,引用计数为2
}
cout << "引用计数:" << ptr2.use_count() << endl;//是多个指针指向了同一个内存空间
//ptr3作用域结束,ptr3没有了,但内存空间没有释放,引用计数为1
}
void test11()
{
//已经知道了,可以使用智能指针指向一个int类型,其他类型类似,
//但这里想深入理解如果类型是指针会怎样
int a = 10;
shared_ptr<int*>ptr(new int* (&a));
cout << *ptr << endl;
cout << **ptr << endl;
//可以看到,我们使用了指针指向了我们在堆上开辟的指针类型int*的
//跟一个二级指针类似
int b = 20;
int* bptr = &b;
shared_ptr<int**>ptr1(new int** (&bptr));
cout << *ptr1 << endl;
cout << **ptr1 << endl;
cout << ***ptr1 << endl;
//如果类型是 二级指针,那么智能指向二级指针后,就是一个三级指针
}
class A
{
public:
A(int age)
{
m_age = age;
cout << "construct A(int)" << age << endl;
}
A(char* name)
{
memset(m_name, 0x00, sizeof(m_name));
strcpy(m_name, name);
cout << "construct A(char*)" << name << endl;
}
~A()
{
cout << "destruct A" << endl;
}
private:
int m_age;
char m_name[16];
};
void test12()
{
shared_ptr<A>ptr = make_shared<A>(50);
char a[] = "zhangsan";
shared_ptr<A>ptr1 = make_shared<A>(a);
}
void test13()
{
//reset()函数的作用:改变指针的指向
shared_ptr<int>ptr = make_shared<int>(100);
shared_ptr<int>prt1 = ptr;
cout << "引用计数:" << ptr.use_count() << endl;
ptr.reset(new int);
cout << "引用计数" << ptr.use_count() << endl;
}
//unique_ptr
void test14()
{
unique_ptr<A>ptr(new A(50));
//unique_ptr<A>ptr1 = ptr;错误,unique_ptr的引用计数不能超过1
unique_ptr<A>ptr1=move(ptr);//ptr不再指向A了,由ptr1拥有
unique_ptr<A>ptr2 = make_unique<A>(100);
}
//数组对象的
void test15()
{
shared_ptr<A>ptr(new A[5]{20,20,20,20,20}, [](A* p) {
delete[]p;//析构数组
});
}
//指针的使用
void test17()
{
//智能指针如何去使用
//使用shared_ptr创建数组
shared_ptr<int>ptr(new int[10]);
shared_ptr<char>ptr1 = make_shared<char>();
int* pp= ptr.get();//获取指针的资源之后就可以像使用指针一样去使用
int* p = pp;
for (int i = 0; i < 10; i++)
{
*pp = 10;
pp++;
}
pp = p;
for (int i = 0; i < 10; i++,pp++)
{
cout << (*pp) << endl;
}
}
c++11新增的重要的知识点已经讲得差不多了,今天我们还得深入的理解C++的Lambda表达式的使用,因为对于C++的回调函数来说Lambda表达式式非常好用的,尤其是使用STL的时候,我们很多时候要提供函数来实现自己想要的功能的。
C++11中的Lambda表达式用于定义并创建匿名的函数对象,以简化编程工作。首先看一下Lambda表达式的基本构成:
[capture](parameters) mutable ->return-type
{
statement
}
[函数对象参数](操作符重载函数参数)mutable ->返回值{函数体}
有了这个结构体,我们说一下如何使用。
首先说一下这个Lambda表达式必须有的结构
[](){}
就是这三个括号,其他的东西可根据需要增加。
【】括号中可以增加什么
① 函数对象参数;
[],标识一个Lambda的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义Lambda为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下形式:
空。没有使用任何函数对象参数。
=。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
&。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
this。函数体内可以使用Lambda所在类中的成员变量。
a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。
&a。将a按引用进行传递。
a, &b。将a按值进行传递,b按引用进行传递。
=,&a, &b。除a和b按引用进行传递外,其他参数都按值进行传递。
&, a, b。除a和b按值进行传递外,其他参数都按引用进行传递。
class B
{
public:
int a;
int b;
int c;
//4.this
void test()
{
//函数嵌套lambda,lambda作用域下是不能够访问类中成员的
//auto fun4 = []() {cout << a << endl; };
auto fun4_1 = [=]() {cout << a << endl; };
auto fun4_2 = [this]() {cout << b << endl; };
auto fun4_3 = [&]() {cout << c << endl; };
fun4_1();
fun4_2();
fun4_3();
}
B() { a = 10; b = 20; c = 30; };
~B() {};
};
//测试[]中的参数
void test16()
{
//1.空
auto fun1 = []() {return 1+2; };//返回1+2
cout <<"1.空:"<< fun1() << endl;
//2.=(值传递)
int a = 10;
//auto fun2 = []() {cout << a << endl; }//报错,如果[]为空,a在lambda中是不知道
cout <<"a的内存地址:"<< &a << endl;
auto fun2 = [=]() {
cout << "2.=:"<<endl;
cout<<"a的值:" << a << endl;
cout << "[=]的传递a的地址:" << &a << endl;//与a的地址不同
//a = 20;报错,因为值传递是没有办法去修改a的值的
int b = a * 2; //那值传递有什么用
cout <<"b的值:" <<b << endl; };
fun2();
//3.&(引用传递)
auto fun3 = [&]() {
cout << "3.&" << endl;
cout<<"[&]的传递a的地址:"<<&a << endl;//与a的地址相同
a = 20; //修改a的值
cout <<"[&]的传递,修改a的值:"<< a << endl;
};
fun3();
cout << "a最后的值:" << a << endl;
//4.this
B classB;
auto fun4 = [&classB]() {classB.test(); };
//fun4();
//classB.test();
int b = 20;
auto fun5 = [&]() {fun4(); };
fun5();
}
② 操作符重载函数参数;
标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递。
//测试()中的参数
void test18()
{
vector<int>ve;
for (int i = 0; i < 10; i++)
{
ve.push_back(i);
}
//查找容器中的满足大于5的
auto l=find_if(ve.begin(), ve.end(), [](int v) {
return v > 5;
});
cout << *l << endl;
}
③ 可修改标示符;
mutable声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)。
//测试mutable
void test19()
{
int a = 10;
auto l = [a]() {
//报错a = 100;
};
auto ll = [a]()mutable {
a = 100;
};
//修改的只是拷贝,原先的值是没有修改的
cout << a << endl;
}