一. 智能指针
一般在类中的不同对象之间需要共享数据时,会用到动态内存
1. shared_ptr
初始化:
不能直接将原生指针赋值给shared_ptr,要用构造函数初始化或者reset()函数
shared_ptr<int> p(new int(5)); //第一种方式
shared_ptr<int> p = make_shared<int>(5); //第二种方式
shared_ptr<int> p = new int(5); //错误,shared_ptr的构造函数是explict的,禁止隐式转换
p = new int(5); //也是错误的,要用reset函数
p = q; //q是另一个shared_ptr,正确的
成员函数:
p.reset() // 将p置空,同时p指向对象的引用计数减1
p.reset(new int(5));
p.get(); //获得p的原生指针,尽量不要用
p.unique() 对象的指针为1时返回true,否则为false //不用记
p.use_count() 速度慢,共享对象的指针个数 //不用记
使用注意事项:
不要把原生指针和智能指针一其使用;
- 不要用相同的内置指针初始化多个shared_ptr;(也算把原生指针和智能指针一其使用的情况,应该用
make_shared<T>()
来初始化; - 不要把原生指针和智能指针一其使用:
(1)尽量不要用get,因为get会返回原生指针(比如get()返回的指针如果被delete了,则shared_ptr出错,或者用get()返回的指针初始化另一个shared_ptr,则其中一个计数为0被释放后,另一个出错——此时和1中类似)
2. unique_ptr
某一时刻对象只能有一个unique_ptr,因此unique_ptr不支持拷贝,赋值
初始化方法:用原生指针初始化构造
unique_ptr<int> p(new int(5));
unique_ptr<int> p = new int(5); //错误
成员函数:
p.release() //p放弃对对象的控制权,p置空,返回对象的原生指针。该函数不能单独出现,很危险,因为会造成内存泄漏。p放弃控制权了,内存还没释放,又没有其他指针指向该内存,该内存无法释放。
解决方法:
(1)auto q = p.release();
(2)q.reset(p.release()); //q是另一个unique_ptr,reset不存在release的问题,如果q指向其他对象,则原来的内存会被释放
总之,要找到一个指针指向p原来的内存。
3. weak_ptr
一般会将weak_ptr绑定到一个shared_ptr上,但不会改变shared_ptr的引用计数
初始化方式:
weak_ptr<int> p(q); //q是一个shared_ptr
成员函数
p.reset(); //将p置空
p.lock(); //如果p指向对象不存在,则返回空的shared_ptr,如果存在则返回一个该对象的shared_ptr,一般用p前都需要用这个判断,因为weak_ptr的对象有可能不存在
————————————————————————————————————
二 allocator类
用于将内存分配和赋值分开。具体过程为:
allocator<T> p;
p.allocate(n); //分配原始内存,不构造
p.construct(); //开始构造每一个对象
p.destroy(); //销毁每一个对象(如果对象有new空间,也一起删除)
p.deallocate(); //删除该内存
三 虚函数
- 重载,重写,重定义
(1)重载:
a. 同一个作用域内
b. 两函数的函数名相同,但是参数不能完全相同,可以是参数类型不同或者是参数个数不同,至于返回值,不影响重载
(2)重写(覆盖)
a. 不同的范围,分别位于基类和派生类中
b. 是虚函数
c. 子类中对应的虚函数函数名必须相同,参数列表必须相同,返回值可以不相同,但是必须是父子关系的指针或引用。
(3)重定义(隐藏)
a. 子类实现了一个和父类名字一样的函数,子类的函数就把父类的同名函数隐藏了(只关注函数名,和参数与返回值无关)(即使是虚函数,若参数不同也会隐藏)
class A
{
public:
virtual int func();
}
class B:public A
{
int func(int);
}
B b;
A* p=b;//基类指针指向派生类
p->func(); //调用的是A::func()
可以这样记忆:
基类的成员在子类中要么不管了(此时它还存在于子类中),要么重写(此时相当于子类基类函数都存在),要么重定义(此时只存在子类的函数)
重写是基类和子类的函数都存在,当用指针调用函数时,根据情况来选择用哪个;
重定义是子类将基类的函数完全隐藏,此时不管怎么调用都是子类的那个函数。
- 虚函数
虚函数要求在子类中的函数名,形参必须与基类完全一致,至于返回值要近似一致
class A {virtual A* func();}
class B:public A
{B* func();} //返回值近似一致,要求从B到A的类型转换是合法的
多态性要求:
(1)必须是基类指针或者引用调用函数(不可以是对象直接调用,若是对象直接调用则会调用对象所对应的那个函数)
(2)必须是虚函数(不可以是普通的函数,如果是普通函数而指针是基类指针,因此会调用基类对应的函数)
- 子类的作用于是嵌套在父类的作用域之内的,当在子类中找不到对应变量或者成员时会去父类中查找