iv{1, 2, 3};模板类map 赞 踩 声明:学习资源来源于中国MOOC,此处仅供总结学习。 普通变量可以在类里面直接赋值 用于定义变量,编译起可以自动判断变量的类型 但是不能如此定义,如下图: 由于在c++中NULL = 0,此时指针为空,是整数类型,而nullptr是字符类型字面值,且nullptr不能自动转换成整型。 所谓的右值引用,首先当右值的一般是不能取地址的参数,比如常数,临时对象等等,那么为了就为右值创建名称来引用即可。 而变量就可以取地址,这叫左值引用。 一般格式: 编译器能自动生成类之间赋值、拷贝构造函数,在一定程度上减轻了代码量,但对于某些特定情况下,我们是不允许对象之间进行拷贝与赋值的,那么这时候,我们就需要考虑将拷贝、赋值构造函数禁用了,那么如下例使用: 正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。 正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。 形式: 定义规则: 注意:“->返回值类型”也可以没有,没有则编译器自动判断返回值类型。 示例: 输出: 11 2 33 4 1).声明式编程风格:就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或者函数对象。以更直接的方式去写程序,好的可读性和可维护性。 2).简洁:不需要额外再写一个函数或者函数对象,避免了代码膨胀和功能分散,让开发者更加集中精力在手边的问题,同时也获取了更高的生产率。 3).在需要的时间和地点实现功能闭包,使程序更灵活。 示例1: 示例2: 由于用派生类指针引用基类的对象。这种引用方式会导致语法错误。派生类指针必须先强制转换为基类指针,这种方法是安全的。 执行效果 经常写代码的同学肯定或多或少会遇到各种程序运行的异常,经常的原因是要么代码的质量不高,存在bug;要么输入的数据不符合设计的要求;要么算法设计考虑不周全等等。 那么在c++11中,try与catch两个函数常用来进行异常处理: 执行效果 异常的再抛出 执行效果 如果您想让 catch 块能够处理 try 块抛出的任何类型的异常,则必须在异常声明的括号内使用省略号 …,如下所示: C++标准库中有一些类代表异常,这些类都是从exception类派生而来。 C++运算符typeid是单目运算符,可以在程序运行过程中获取一个表达式的值的 类型。typeid运算的返回值是一个type_info类的对象,里面包含了类型的信息。 执行效果 Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。
c++11特性_shared ptr无法托管数组
2020.02.10
一致初始化方法
int arr[3]{1, 2, 3};
string str{"Hello World"};
vector<int> iv{1, 2, 3};
map<int, string> mp{{1, "a"}, {2, "b"}};
int * p = new int[20]{1,2,3};
成员变量默认初始值
class A{
public:
int num = 10;//定义时直接赋值
int n ;
}
int main()
{
A a;
cout<< a.num <<endl;
return 0;
}
auto关键字
auto num1 = 100;//整型,相当于int
auto p = new A();//类指针型;
auto num2 = 5201314LL;//长整型
map<string,int ,less<string> >mp;
for(auto i = 0;i != mp.end();i++)
cout<< i->first <<" "<< i->second << endl;
//i的类型是map<string,int,less<string> >::iterator;
注意使用表达式一定要在auto的基础上加decltype,不然会出错,如图
为什么decltype放在函数后面呢?因为auto在这里的作用称为返回值占位,它只是为函数返回值占了一个位置,真正的返回值是后面的decltype( x + y);如果放置在前面,那么`decltype( x + y) add(T1 x,T2 y),其中使用声明的时候x与y还没有定义,会编译错误。
如例1:
例2:
智能指针shared_ptr
#include<memory>
share_ptr<T>ptr(new T)
;此后ptr就可以像 T* 类型的指针一样来使用,即 *ptr 就是用new动态分配的那个对象,而且不必操心释放内存的事。
和
因为ptr1和ptr2都是托管p,但是由于同时定义时,他们不会共享一个托管指针的技术,会各自计数,都是1,那么会导致p的析构函数调用两次,严重会导致程序崩溃。
空指针nullptr
右值引用和move语义
class A{ };
A &&T = A();//临时对象,右值引用;注意形式一般是“&&”
类型 && 引用名 = 右值表达式;
而右值引用的主要目的是提高程序运行的效率,减少需要进行深拷贝的对象进行深拷贝 的次数。#include<iostream>
#include<string>
#include<cstring>
using namespace std;
class String{
public:
char *str;
String ():str(new char[1]){ str[0] = 0;}
String (const char *s){
str = new char[strlen(s) + 1];
strcpy(str,s);
}
String(const String & s) {
cout << "copy constructor called" << endl;
str = new char[strlen(s.str)+1];
strcpy(str,s.str);
}
String &operator=(const String &s){
cout << "copy operator= called" << endl;
if(str != s.str){
delete []str;
str = new char [strlen(s.str) + 1];
strcpy(str,s.str);
}
return *this;
}
String(String && s):str(s.str) {
cout << "move constructor called"<<endl;
s.str = new char[1];
s.str[0] = 0;
}
String & operator = (String &&s) {
cout << "move operator= called"<<endl;
if (str!= s.str) {
delete [] str;
str = s.str;
s.str = new char[1];
s.str[0] = 0;
}
return *this;
}
~String() { delete [] str; }
};
template <class T>
void MoveSwap(T& a, T& b){
T temp(move(a));// std::move(a)为右值,这里会调用move constructor
a = move(b);//move(b)为右值,因此这里会调用move assigment
b = move(temp);//move(temp)为右值,因此这里会调用move assigment
}
int main()
{
String s;
s = String("ok");
cout << "******" << endl;
String && r = String("this");
cout << r.str << endl;
String s1 = "hello",s2 = "world";
MoveSwap(s1,s2);
cout << s2.str << endl;
return 0;
}
规则·:
C++11 标准引入了一个新特性:"=delete"函数。程序员只需在函数声明后加上“=delete;”并且需要注意的是必须在函数第一次声明的时候将其声明为 = delete 函数,否则编译器会报错。
无序容器(哈希表)
正则表达式
点击了解更多指令规则
Lambda表达式
[外部变量访问方式说明符] (参数表) ->返回值类型 {
语句组
}(参数1值,参数2值,...)
[ ] 不使用任何外部变量 ;
[=] 以传值的形式使用所有外部变量;
[&] 以引用形式使用所有外部变量 ;
[x, &y] x 以传值形式使用,y 以引用形式使用;
[=,&x,&y] x,y 以引用形式使用,其余变量以传值形式使用;
[&,x,y] x,y 以传值的形式使用,其余变量以引用形式使用;int a[4] = { 4,2,11,33};
sort(a,a+4,[ ](int x,int y)->bool { return x%10 < y%10; });
for_each(a,a+4,[ ](int x) {cout << x << " " ;} ) ;
lambda表达式有如下优点:
其中for_each()用于访问每一个元素成员。
实现递归的斐波那契数列#include<iostream>
#include<algorithm>
#include <functional>
using namespace std;
int main()
{
function<int(int)> fib = [&fib](int n)
{ return n <= 2 ? 1 : fib(n - 1) + fib(n - 2); };
cout << fib(5) << endl;
return 0;
}
//function<int(int)> 表示返回值为 int,并不是将返回值传给fib,而是<>中参数, 有一个int参数的函数
//而此处fib可以当作函数指针等运用。
类型强制转换
static_cast用来进用行比较“自然”和低风险的转换,比 如整型和实数型、字符型之间互相转换。
static_cast不能来在不同类型的指针之间互相转换,也不 能用于整型和指针之间的互相转换,也不能用于不同类型的 引用之间的转换。
reinterpret_cast用来进行各种不同类型的指针之间的转换、不同 类型的引用之间转换、以及指针和能容纳得下指针的整数类型之间的转换。转换的时候,执行的是逐个比特拷贝的操作。
用来进行去除const属性的转换。将const引用转换成同类型的非const引用,将const指针转换为同类型的非const指针时用它。例如:const string s = “Inception”;
string & p = const_cast<string&>(s);
string * ps = const_cast<string*>(&s); // &s的类型是const string *
#include<iostream>
#include<string>
using namespace std;
class base {
public:
virtual ~base(){ }
};
class based_on :public base { };
int main()
{
base b;
based_on d;
based_on* p;
p = reinterpret_cast<based_on*>(&b);//基类指针,转化成派生类,不检查错误
if (p == NULL)
cout << "unsafe reinterpret_cast" << endl;
p = dynamic_cast<based_on*>(&b);//下行,基类指针,转化成派生类,检查错误
if(p == NULL)
cout << "unsafe dynamic_cast1" << endl;
p = dynamic_cast<based_on*>(&d);//上行,派生类指针,检查错误
if(p == NULL)
cout << "unsafe dynamic_cast2" << endl;
return 0;
}
满足不出错的情况一般是子类转化成父类指针或引用,子类与子类的转化等。
异常处理
那么如何正确处理发生的异常也是值得学习的。#include<iostream>
#include<string>
using namespace std;
int main()
{
double m, n;
cin >> m >> n;
try {
cout << "before dividing." << endl;
if (n == 0)
throw - 1;//抛出-1整型异常
if (m == 0)
throw -0.2;
else
cout << m / n << endl;
cout << "after dividing" << endl;
}
catch (double d) {
cout << "catch(double) " << d << endl;
}
catch (int e) {
cout << "catch(int) " << e << endl;
}
cout << "finished" << endl;
return 0;
}
只要抛出一个异常try内的程序就会结束进行,跳到catch函数处。
如果一个函数在执行的过程中,抛出的异常在本函数内就被catch块捕获并处理了, 那么该异常就不会抛给这个函数的调用者(也称“上一层的函数”);如果异常在 本函数中没被处理,就会被抛给上一层的函数。#include<iostream>
#include<string>
using namespace std;
class CException {
public:
string msg;
CException(string s) :msg(s) { }
};
double Devide(double x, double y)
{
if (y == 0)
throw CException("devided by zero");//跳出子函数
cout << "in Devide" << endl;
return x / y;
}
int CountTax(int salary)
{
try {
if (salary < 0)
throw - 1;
cout << "counting tax" << endl;
}
catch (int) {//本函数内就被catch块捕获并处理
cout << "salary < 0" << endl;
}
cout << "tax counted" << endl;
return salary * 0.15;
}
int main() {
double f = 1.2;
try {
CountTax(-1);
f = Devide(3, 0); //抛出的是临时对象,不会改变f的值,也没有重载
cout << "end of try block" << endl;
}
catch (CException e) {//捕捉处理
cout << e.msg << endl;
}
cout << "f=" << f << endl;
cout << "finished" << endl;
return 0;
}
其中throw 语句的操作数可以是任意的表达式,表达式的结果的类型决定了抛出的异常的类型。try{
// 保护代码
}
catch(...){
// 能处理任何异常的代码
}
C++标准异常类
详情,点击了解更多
运行时类型检查
#include<iostream>
#include<typeinfo>
using namespace std;
class A { };
class a:public A{ };
class B {
virtual void show(){}
};
class b:public B{ };
int main()
{
//基本类型
char c;
char* p = nullptr;
cout << "typeid(int).name "<< typeid(int).name() << endl;
cout << "typeid(char).name " << typeid(char).name() << endl;
cout << "typeid(p).name " << typeid(p).name() << endl;
cout << "typeid(*p).name " << typeid(*p).name() << endl;
//非多态类型
a t;
A* aa = &t;
cout << "typeid(a).name " << typeid(a).name() << endl;
cout << "typeid(*aa).name " << typeid(*aa).name() << endl;
//多态类型
b tt;
B* bb = &tt;
cout << "typeid(b).name " << typeid(b).name() << endl;
cout << "typeid(*bb).name " << typeid(*bb).name() << endl;
}