一、智能指针
智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象。标准库提供的两种智能指针的区别在于管理底层指针的方法不同,shared_ptr允许多个指针指向同一个对象,unique_ptr则“独占”所指向的对象。标准库还定义了一种名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象,这三种智能指针都定义在memory头文件中。
#include <iostream>
#include <memory>
using namespace std;
class Test
{
public:
Test()
{
cout<<"Test的构造函数"<<endl;
}
~Test()
{
cout<<"Test的析构函数"<<endl;
}
void print()
{
cout<<"XXXX"<<endl;
}
};
void f1()
{
Test *t1 = new Test;
}
void f2()
{
auto_ptr<Test> my_memory(new Test);
my_memory->print();
}
int main(int argc, char const *argv[])
{
f1();
f2();
return 0;
}
二、模板
2.1 概念:将函数的返回值和参数的类型参数化,也叫范型编程
2.2 函数模板
#include <iostream>
using namespace std;
int add(int x, int y) //当模板函数和原函数同时存在时,优先调用原来的函数
{
cout<<"int add(int x, int y)"<<endl;
return x + y;
}
double add(double x, double y)
{
cout<<"double add(double x, double y)"<<endl;
return x + y;
}
template <typename T> //声明一个虚拟类型T,模板函数不能做默认类型转换
T add(T x, T y)
{
cout<<"template <typename T>"<<endl;
return x + y;
}
template <typename T1, typename T2>
void print(T1 x, T2 y)
{
cout<<x<<" "<<y<<endl;
}
int main(int argc, char const *argv[])
{
cout<<add(1,2)<<endl; //隐式调用
cout<<add(1.11, 2.22)<<endl;
cout<<add<int>(1,'a')<<endl; //显示调用
print(1,'a');
return 0;
}
2.3 类模板
2.3.1 类模板的定义:类模板中定义的函数类型可以用在类声明和类实现中,类模板的目的同样是将数据类型参数化
#include <iostream>
using namespace std;
template <typename T, typename U>
class Test
{
private:
T a;
U b;
public:
Test(T a, U b)
{
this->a = a;
this->b = b;
}
void show()
{
cout<<a<<" "<<b<<endl;
}
};
int main(int argc, char const *argv[])
{
Test<int,char> t(1,'a'); //类模板创建时一定要显示调用
t.show();
return 0;
}
类模板中的继承
#include <iostream>
using namespace std;
template <typename T, typename U>
class Parent
{
protected:
T a;
U b;
public:
Parent(T a, U b)
{
this->a = a;
this->b = b;
}
void show()
{
cout<<a<<" "<<b<<endl;
}
};
class Child:public Parent<int, char> //模板类派生普通类,继承的同时对基类实例化
{
public:
Child(int a, char b):Parent(a,b)
{
}
void show()
{
cout<<a<<" "<<b<<endl;
}
};
template <typename T, typename U>
class Child2:public Parent<T,U> //模板类派生模板类,继承的同时不需要对parent进行实例化
{
private:
U c;
public:
Child2(T a, U b, U c):Parent<T,U>(a,b)
{
this->c = c;
}
void show()
{
cout<<this->a<<" "<<this->b<<" "<<c<<endl;
}
};
int main(int argc, char const *argv[])
{
Child c1(1,'a');
c1.show();
Child2<int,double> c2(1,2.22,3.33);
c2.show();
return 0;
}
模板的声明
#include <iostream>
using namespace std;
template <typename T> //类模板的声明的作用域仅对下一个函数或者类有效
class Test
{
private:
int a;
public:
Test(T a);
void show();
~Test();
};
template <typename T>
Test<T>::Test(T a) //Test<T>表示Test是模板类,不是普通类
{
this->a = a;
}
template <typename T>
void Test<T>::show()
{
cout<<a<<endl;
}
template <typename T>
Test<T>::~Test()
{
cout<<"Test的析构函数"<<endl;
}
int main(int argc, char const *argv[])
{
Test<int> t(1);
t.show();
return 0;
}
模板中的static关键字
#include <iostream>
using namespace std;
template <typename T> //类模板的声明的作用域仅对下一个函数或者类有效
class Test
{
private:
int a;
public:
static int count; //类外面初始化
Test(T a);
void show();
~Test();
};
template <typename T>
int Test<T>::count = 0;
template <typename T>
Test<T>::Test(T a) //Test<T>表示Test是模板类,不是普通类
{
this->a = a;
}
template <typename T>
void Test<T>::show()
{
cout<<a<<endl;
}
template <typename T>
Test<T>::~Test()
{
cout<<"Test的析构函数"<<endl;
}
int main(int argc, char const *argv[])
{
Test<int> t1(1);
Test<int> t2(1);
Test<int> t3(1);
Test<int> t4(1);
Test<int> t5(1);
Test<int> t6(1);
Test<char> t7('a');
Test<char> t8('b');
Test<char> t9('c');
Test<char> t10('d');
cout<<Test<int>::count<<endl;
cout<<Test<char>::count<<endl;
return 0;
}
三、异常
3.1 什么是异常?
异常处理就是处理程序中的错误,所以错误就是指程序在运行期间的一些异常举动(栈溢出,读取文件不存在,野指针等)
3.2 异常的语法
抛出异常: throw关键词, 当执行throw关键词后,抛出异常
检测异常:try语句会检测异常
捕获异常:catch(异常类型 变量名){处理语句}
#include <iostream>
using namespace std;
int Div(int x, int y) //除
{
if(0 == y)
{
throw 0; //抛出异常
}
return x / y;
}
int main(int argc, char const *argv[])
{
int a, b;
cin>>a>>b;
try
{
cout<<Div(a,b)<<endl;
}
catch(int)
{
cout<<"zero excetion!"<<endl;
}
cout<<"hello world"<<endl;
return 0;
}
3.3 异常的思想
#include <iostream>
using namespace std;
int Div(int x, int y) //除
{
if(0 == y)
{
throw 0; //抛出异常
}
return x / y;
}
int main(int argc, char const *argv[])
{
int a, b;
cin>>a>>b;
try //把可能异常的语句放在try语句中
{
cout<<Div(a,b)<<endl;
}
catch(int)
{
cout<<"zero excetion!"<<endl;
}
cout<<"hello world"<<endl;
return 0;
}
3.4 异常的声明
#include <iostream>
using namespace std;
//int Div(int x, int y) throw(int , char); //只能抛出整型或者字符型异常
//int Div(int x,int y) throw(); //不能抛出任何异常
int Div(int x,int y); //可能抛出任何异常
int main(int argc, char const *argv[])
{
int a, b;
cin>>a>>b;
try
{
cout<<Div(a,b)<<endl;
}
catch(int)
{
cout<<"zero exception"<<endl;
}
catch(char)
{
cout<<"char exception"<<endl;
}
catch(double)
{
cout<<"double exception"<<endl;
}
cout<<"hello world"<<endl;
return 0;
}
int Div(int x, int y) //除
{
if(0 == y)
{
throw 1.11; //抛出异常
}
return x / y;
}
3.5 异常的对象
#include <iostream>
using namespace std;
class Test
{
public:
Test()
{
cout<<"Test的构造函数"<<endl;
}
Test(const Test &is_obj) //拷贝构造函数
{
cout<<"Test的拷贝构造函数"<<endl;
}
void print()
{
cout<<"Test exception"<<endl;
}
~Test()
{
cout<<"Test的析构函数"<<endl;
}
};
int Div(int x, int y) //除
{
if(0 == y)
{
//throw 1.11; //抛出异常
throw new Test;
}
return x / y;
}
int main(int argc, char const *argv[])
{
int a, b;
cin>>a>>b;
try
{
cout<<Div(a,b)<<endl;
}
catch(Test t) //调用了拷贝构造函数
{
t.print();
}
catch(Test &t) //引用
{
t.print();
}
catch(Test *t) //Test *t = new Test;
{
t->print();
delete t; //需要手动释放
}
cout<<"hello world"<<endl;
return 0;
}
3.6 标准异常库
execption基类提供一个函数:what(),用于返回错误信息
virtual const char * what() const throw();
//exception 基类提供了一个函数: what() 用于返回错误信息
//virtual const char * what()const throw();
#include <iostream>
#include <exception>
using namespace std;
class Test
{
private:
int id;
public:
Test(int i)
{
if(i < 0)
{
throw out_of_range("id不可以小于0");
}
id = i;
}
};
int main(int argc, char const *argv[])
{
try
{
Test t(-1);
}
catch(exception& e)
{
cout << e.what() << '\n';
}
return 0;
}
类型转换
C语言强制类型转换存在的问题
1.过于粗暴
2.难于定位
C++中的类型转换
static_cast 强制类型转换
限制条件:1.用于基本类型之间的转换,不能用于普通指针之间的转换
2.用于有继承关系的对象之间的转换和类指针之间的 转换
3.static_cast 是在编译期间进行转换的,无法在运行时检查类型,所以可能存在风险
#include <iostream>
using namespace std;
class Parent
{
};
class Child:public Parent
{
};
int main(int argc, char const *argv[])
{
int a = 1;
char ch = 'a';
a = static_cast<int>(ch); //用于普通类型之间的转换
cout<<a<<endl;
// int *p = static_cast<int *>(&ch); //不能用于普通指针之间的类型转换
Parent p;
Child c;
p = static_cast<Parent>(c); //用于有继承关系的类对象之间的转换
// cout<<p<<endl;
Parent *p1 = static_cast<Parent *>(&c); //用于类对象指针之间的转换
cout<<p1<<endl;
return 0;
}
reinterpret_cast
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
int a = 100;
int b = 10;
char *p = reinterpret_cast<char *>(&a); //用于普通指针类型之间的转换(不安全)
cout<<*(p+1)<<endl;
int *q = reinterpret_cast<int *>(100); //用于数字和指针之间的转换,很容易出现野指针
*q = 1;
return 0;
}
const_cast
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
const int a = 1; //常量
int *p = const_cast<int *>(&a);
*p = 100;
cout<<a<<endl;
const int &m = 1; //常量
int &n = const_cast<int &>(m);
n = 100;
cout<<m<<endl;
cout<<n<<endl;
return 0;
}
dynamic_cast
#include <iostream>
using namespace std;
class Parent
{
public:
virtual void show()
{
}
};
class Child: public Parent
{
public:
void show()
{
}
};
int main(int argc, char const *argv[])
{
Child *c = new Child;
delete c;
c = dynamic_cast<Child *>(new Parent); //派生类指针指向基类对象(错误)
if(c == NULL)
{
cout<<"转换失败"<<endl;
}
else
{
cout<<"转换成功"<<endl;
delete c;
}
return 0;
}