C++ 学习笔记之(19) new、delete表达式、RTTI(运行时类型识别)、枚举、类成员指针、嵌套类、局部类、位域、volatile、extern C

C++ 学习笔记之(19) new、delete表达式、RTTI(运行时类型识别)、枚举、类成员指针、嵌套类、局部类、位域、volatile、extern C

控制内存分配

重载newdelete

  • new表达式原理

    string *sp = new string("a value");  // 分配并初始化一个 string 对象
    string *arr = new string[10];  // 分配 10 个默认初始化的 string 对象
    • 调用标准库函数operator newoperator new[],该函数分配足够大的、原始的、未命名的内存空间以便存储特定类型的对象(或者对象的数组)
    • 编译器运行相应的构造函数构造对象,并传入初始值
    • 对象被分配空间并构造完成,返回一个指向该对象的指针
  • delete表达式原理

    delete sp;  // 销毁 *sp, 然后释放 sp 指向的内存空间
    delete [] arr; // 销毁数组中的元素,然后释放对应的内存空间
    • 对动态分配的对象或数组中的而元素执行相应的析构函数
    • 编译器调用标准库函数operator delete(或operator delete[])释放内存空间
  • 标准库定义oeprator new函数和operator delete函数的8个重载版本,前四个可能抛出bad_alloc异常

operator_new_and_delete_functions

  • 自定义版本必须位于全局作用域或类作用域中
  • 上述运算符函数定义为类的成员时,是隐式静态的。因为new用在对象构造之前,delete用在对象销毁之后,故必须是静态的,且不能操纵类的任何数据成员
  • newnew[]的返回类型必须是void *, 第一个形参类型必须是size_t, 且该形参不能含有默认实参,但可提供额外形参。函数形式void *operator new(size_t, void*);,不可被重载。
  • deletedelete[]函数的返回类型必须是void, 第一个形参类型必须是void*。用指向待释放内存的指针来初始化void*形参

    • 实际上自定义的是opearot new函数,并非new表达式。new表达式无法改变,自定义operator newoperator delete函数的目的在于改变内存分配的方式。

定位new表达式

  • operator new函数分配的内存空间应该使用new定位new(placement new)形式构造对象

placement_new_format

  • place_address为指针, initializers为初始值列表,用于构造新分配的对象
  • 当只传入一个指针类型的实参时,定位new表达式构造对象但是不分配内存。定位new表达式使用operator new(size_t, void*)函数,该函数不分配内存,仅返回指针实参。然后由new表达式负责在指定的地址初始化对象
  • 传给allocatorconstruct的指针必须指向同一个allocator对象分配的孔家,但是传给定位new的指针无需指向operator new分配的内存,甚至不需要指向动态内存
  • allocatordestroy类似,调用析构函数会销毁对象,但是不会释放内存

运行时类型识别

运行时类型识别(run-time type identification RTTI)由连个运算符实现

  • typeid运算符,用于返回表达式的类型
  • dynamic_cast运算符,用于将基类的指针或引用安全地转换成派生类的指针或引用
  • 使用情况:使用基类对象的指针或引用执行某个派生类操作并且该操作不是虚函数。
  • 使用RTTI时,最好定义虚函数而非直接操作类型管理

dynamic_cast运算符

  • dynamic_cast运算符使用形式(其中type必须是类类型, 且通常含有虚函数)
    • dynamic_cast<type*>(e)e必须是一个有效的指针
    • dynamic_cast<type&>(e)e必须是一个左值
    • dynamic_cast<type&&>(e)e不能是左值
  • e的类型必须符合以下三个条件中的任意一个,转换才能成功
    • e的类型是目标type的公有派生类
    • e的类型是目标type的公有基类
    • e的类型就是目标type的类型
  • dynamic_cast转换失败情况
    • 若转换目标是指针类型:失败结果为0
    • 若转换目标是引用类型:失败抛出bad_cast异常
// 指针类型的 dynamic_cast
// bp 指针指向基类 Base(至少含有一个虚函数), dp 指针指向公有派生类 Derived
if(Derived *dp = dynamic_cast<Derived*>(bp))
{
    // 使用 dp 指向的 Derived 对象
}else {  // bp 指向一个 Base 对象
    // 使用 bp 指向的 Base 对象
}

// 引用类型的 dynamic_cast, 因为不存在控引用,故使用异常捕获
void f(const Base &b)
{
    try{
        const Derived &d = dynamic_cast<const Derived&>(b);
        // 使用 b 引用的 Derived 对象
    }catch(bad_cast){
        // 处理类型转换失败的情况
    }
}

typeid

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值