C++Primer笔记

. 智能指针

一般在类中的不同对象之间需要共享数据时,会用到动态内存

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() 速度慢,共享对象的指针个数 //不用记

使用注意事项:
不要把原生指针和智能指针一其使用;

  1. 不要用相同的内置指针初始化多个shared_ptr;(也算把原生指针和智能指针一其使用的情况,应该用make_shared<T>()来初始化;
  2. 不要把原生指针和智能指针一其使用:
    (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. 重载,重写,重定义
    (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()

可以这样记忆:
基类的成员在子类中要么不管了(此时它还存在于子类中),要么重写(此时相当于子类基类函数都存在),要么重定义(此时只存在子类的函数)
重写是基类和子类的函数都存在,当用指针调用函数时,根据情况来选择用哪个;
重定义是子类将基类的函数完全隐藏,此时不管怎么调用都是子类的那个函数。

  1. 虚函数
    虚函数要求在子类中的函数名,形参必须与基类完全一致,至于返回值要近似一致
class A {virtual  A* func();}
class B:public A
{B* func();}  //返回值近似一致,要求从B到A的类型转换是合法的

多态性要求:
(1)必须是基类指针或者引用调用函数(不可以是对象直接调用,若是对象直接调用则会调用对象所对应的那个函数)
(2)必须是虚函数(不可以是普通的函数,如果是普通函数而指针是基类指针,因此会调用基类对应的函数)

  1. 子类的作用于是嵌套在父类的作用域之内的,当在子类中找不到对应变量或者成员时会去父类中查找

猜你喜欢

转载自blog.csdn.net/aikudexue/article/details/89035527