C++面试题补漏

智能指针

1,,你知道智能指针吗?智能指针的原理。
2,常用的智能指针。
3,智能指针的实现。

智能指针是一个类, 智能指针实质是重载了->和*操作符的类,由类来实现对内存的管理,确保即使有异常产生,也可以通过智能指针类的析构函数完成内存的释放。使用shared_ptr避免

这个类的构造函数中传入一个普通指针,析构函数中释放传入的指针。智能指针的类都是栈上的对象,所以当函数(或程序)结束时会自动被释放。所以用起来会更加的安全。

C++11的标准库提供了两种解决问题的思路:1、不允许多个对象管理一个指针(unique_ptr);2、允许多个对象管理同一个指针,但仅当管理这个指针的最后一个对象析构时才调用delete(shared_ptr)。这两个思路的共同点是:只!允!许!delete一次!

## shared_ptr 在将shared_ptr的使用之前,我们首先来看看它的基本实现原理。

刚才说到,当多个shared_ptr管理同一个指针,仅当最后一个shared_ptr析构时,指针才被delete。这是怎么实现的呢?

它的实现是:引用计数(reference counting)。
引用计数指的是,所有管理同一个裸指针(raw pointer)的shared_ptr, 都共享一个引用计数器,每当一个shared_ptr被赋值(或者拷贝构造)给其他shared_ptr时,这个共享的引用计数器就加1,当一个shared_ptr析构或者被用于管理其他裸指针时,这个引用计数器就减1,如果此时发现引用计数器为0,那么说明它是管理这个指针的最后一个shared_ptr了,于是我们释放指针指向的资源。

shared_ptr的使用

分配内存

make_shared(100),或者new,接受指针参数的智能指针构造函数是explicit的,因此,我们不能将一个内置指针隐式转化为一个智能指针,必须使用直接初始化形式。

//make_shared<int>分配一块int类型大小的内存,并值初始化为100
//返回值是shared_ptr类型,因此可以直接赋值给sp
shared_ptr<int> sp = make_shared<int>(100);

//错误! 不会进行隐式转换,类型不符合
shared_ptr<int> sp1 = new int(100);
//正确,直接初始化调用构造函数
shared_ptr<int> sp2(new int(100000));

结论

用shared_ptr, 不用new
使用weak_ptr来打破循环引用
用make_shared来生成shared_ptr
用enable_shared_from_this来使一个类能获取自身的shared_ptr

C++中防止一个类被继承

方法一:
构造函数与析构函数设置为私有,写一个共有的静态的函数来返回一个对象,这种方式和只能在堆上建立对象是一样的。

class Myclass
{
public:
    static Myclass* NewNode()
    {
        return new Myclass();
    }
    static void DeleteNode(Myclass* _Myclass)
    {
        delete  _Myclass;
    }
private:
    Myclass()
    {}
    ~Myclass()
    {}
};
class Child :public Myclass
{
public:
    Child()
    {}
    ~Child()
    {}
};

方法二:
让这个类虚拟继承一个基类,并且作为基类的友元函数,将这个基类的构造方法和析构函数设置成private.
下面我们来看下我们缩写的MyClass类,由于它虚拟继承于Base类,同时作为Base的友元,此时可以访问Base的私有的构造函数和析构函数。
因此它可以在堆上建立对象,也可以在栈上建立对象。

C++类型转换

const_cast 将常量指针或者常量引用转换成非常量的指针或者引用。
static_cast 和C语言风格强制转换的效果基本一样。

static_cast强制转换只会在编译时检查,但没有运行时类型检查来保证转换的安全性。同时,static_cast也不能去掉expression的const、volitale、或者__unaligned属性。

用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。注意:进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。

dynamic_cast

从上边的代码和输出结果可以看出:
对于从子类到基类的指针转换 ,dynamic_cast 成功转换,没有什么运行异常,且达到预期结果
而从基类到子类的转换 , dynamic_cast 在转换时也没有报错,但是输出给 base2sub 是一个 nullptr ,说明dynami_cast 在程序运行时对类型转换对“运行期类型信息”(Runtime type information,RTTI)进行了检查.

这个检查主要来自虚函数(virtual function) 在C++的面对对象思想中,虚函数起到了很关键的作用,当一个类中拥有至少一个虚函数,那么编译器就会构建出一个虚函数表(virtual method table)来指示这些函数的地址,假如继承该类的子类定义并实现了一个同名并具有同样函数签名(function siguature)的方法重写了基类中的方法,那么虚函数表会将该函数指向新的地址。此时多态性就体现出来了:当我们将基类的指针或引用指向子类的对象的时候,调用方法时,就会顺着虚函数表找到对应子类的方法而非基类的方法。因此注意下代码中 Base 和 Sub 都有声明定义的一个虚函数 ” i_am_virtual_foo” ,我这份代码的 Base 和 Sub 使用 dynami_cast 转换时检查的运行期类型信息,可以说就是这个虚函数

此外,dynamic_cast只有在基类存在虚函数(虚函数表)的情况下才有可能将基类指针转化为子类.

new_type 必须是一个指针或引用或“指向 void 的指针”。 如果 new_type 是指针,则expression 的类型必须是指针,如果 type-id 是引用,则expression为左值。 如果转型失败会返回null(转型对象为指针时)或抛出异常(转型对象为引用时)。dynamic_cast 会动用运行时信息(RTTI)来进行类型安全检查,因此dynamic_cast 存在一定的效率损失。

reinterpret_cast

reinterpret_cast是强制类型转换符用来处理无关类型转换的,通常为操作数的位模式提供较低层次的重新解释!但是他仅仅是重新解释了给出的对象的比特模型,并没有进行二进制的转换!
他是用在任意的指针之间的转换,引用之间的转换,指针和足够大的int型之间的转换,整数到指针的转换,在在面的文章中将给出.

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值