zoukankan      html  css  js  c++  java
  • C++学习笔记(十一):void*指针、类型转换和动态内存分配

    void*指针

    void关键字表示“空类型”的概念。但是,这里的“空类型”不表示“任意类型”,而是表示不存在的意思,也就是说C/C++不允许你写语句void a,不存在类型为void的东西.

    void*表示“空类型指针”,与void不同,void*表示“任意类型的指针”或表示“该指针与一地址值相关,但是不清楚在此地址上的对象的类型”。

    类型转换

    C风格转换:

    1 int i;
    2 double d;
    3 
    4 i = (int) d;
    5 //
    6 i = int (d);

    C风格转换在C++中是适用的。但是C++也提供了4种转换方法。

    那为什么还需要一个新的C++类型的强制转换呢?

    新类型的强制转换可以提供更好的控制强制转换过程,允许控制各种不同种类的强制转换。C++中风格是static_cast<type>(content)。C++风格的强制转换其他的好处是,它们能更清晰的表明它们要干什么。程序员只要扫一眼这样的代码,就能立即知道一个强制转换的目的。

    C++转换:

    static_cast(exp)

    用于相关类型之间的转换,诸如:在同一个类的继承层次关系中,向上或向下转换;枚举类型与整数类型之间的转换;浮点类型与指数类型之间的转换。

    static_cast它能在内置的数据类型间互相转换,对于类只能在有联系的指针类型间进行转换。可以在继承体系中把指针转换来、转换去,但是不能转换成继承体系外的一种类型

     1 class A { ... };
     2 class B { ... };
     3 class D : public B { ... };
     4 void f(B* pb, D* pd)
     5 {
     6     D* pd2 = static_cast<D*>(pb);        // 不安全, pb可能只是B的指针
     7     B* pb2 = static_cast<B*>(pd);        // 安全的
     8     A* pa2 = static_cast<A*>(pb);        //错误A与B没有继承关系
     9     ...
    10 }

    reinterpret_cast(exp)

    字面理解即re-interpret,重新解析(释)的意思。故名思意,它主要用于不相关类型之间的转换,好一个英文单词在不同的上下文中,词性和词义可能完全不同。它为不同类型之间转换带来的便利,但是也伴随着风险的,如将一个十六进制整数转换为内存地址(由int-->指针类型,这两种类型完全不关联)。既然是用于不相关类型之间的转换,也就意味着编译器不会做太多的确认和承诺。
    reinterpret_cast方式还有一个特点就是:目标和原始值之间至少有相同的位数,我们可以将转换之后的值再转换回去,而不像其它3种类型可能会导致精度丢失。

    dynamic_cast(exp)

    一种运行时(run-time)检测的类型转换,因此转换可能需要较大的运行时代价,这种类型也是用C-style是无法实现的。主要用于执行类型向下转换和继承之间的转换。

    dynamic_cast 仅能应用于指针或者引用,不支持内置数据类型
    表达式dynamic_cast<T*>(a) 将a值转换为类型为T的对象指针。如果类型T不是a的某个基类型,该操作将返回一个空指针。
    它不仅仅像static_cast那样,检查转换前后的两个指针是否属于同一个继承树,它还要检查被指针引用的对象的实际类型,确定转换是否可行。

    const_cast(exp)

    用于消除变量的const限定,转换之后的变量就不再具有“const”了,如果是一个const指针的话,转换之后可以改变指向而指向其它对象。

    说明:

    通常情况下dynamic_cast最好些,它检查的更严格些,其次是static_cast,而后两者也就是const_cast和reinterpret_cast较之前两者貌似不太常用,而且也不推荐使用,const_cast在用于去除const的地方还是有所发挥的,reinterpret_cast在转换时,不会在内存中进行补足比特位(例如int转换到double,需要补足4字节),这往往是不安全的,而且代码也是不可移植的。

    动态内存分配

    一般来说,编译器将内存分为三部分:静态存储区域、栈、堆。静态存储区主要保存全局变量和静态变量,栈存储调用函数相关的变量、地址等,堆存储动态生成的变量。 在c中是指由malloc,free运算产生释放的存储空间,在c++中就是指new和delete运算符作用的存储区域。

    对象创建的两种方式:

    类示例:

     1 #include <iostream>  
     2 using namespace std;  
     3   
     4 class TestNew  
     5 {  
     6 private:  
     7     int ID;  
     8 public:  
     9     TestNew(int ID);  
    10     ~TestNew();  
    11 };  
    12   
    13 TestNew::TestNew(int ID)  
    14 {  
    15     this->ID = ID;  
    16 }  
    17   
    18 TestNew::~TestNew()  
    19 {  
    20     std::cout<<"对象 "<<this->ID<<" 执行析构函数"<<std::endl;  
    21 }

    方法一:

    ClassName object(param);

    1 TestNew test(1);

    这样就声明了一个ClassName类型的object对象,C++会为它分配足够的存放对象所有成员的存储空间。
    这种方法创建的对象,内存分配是分配到栈中的,由C++缺省创建和撤销,自动调用构造函数和析构函数。
    该方法创建的对象调用类方法时,必须用“.”,而不能用“->”。

    在函数中使用该方法时,函数内局部变量的存储单元都在栈上创建,函数执行结束后在将这些局部变量的内存空间回收。
    在栈上分配内存空间效率很高,但是分配的内存容量有限。

    方法二:

    ClassName *object=new ClassName(param);
    delete object;

    1 TestNew *pTest = new TestNew(1);
    2 delete pTest;

    C++用new创建对象时返回的是一个对象指针,object指向一个ClassName的对象,C++分配给object的仅仅是存放指针值的空间。
    用new 动态创建的对象必须用delete来撤销该对象。只有delete对象才会调用其析构函数。
    new创建的对象不是用“*”或“.”来访问该对象的成员函数的,而是用运算符“->”;

    new创建类对象特点:

    1. new创建类对象需要指针接收,一处初始化,多处使用
    2. new创建类对象使用完需delete销毁
    3. new创建对象直接使用堆空间,而局部不用new定义类对象则使用栈空间
    4. new对象指针用途广泛,比如作为函数返回值、函数参数等
  • 相关阅读:
    Linux下新磁盘挂载
    Centos6.5下Haproxy负载均衡搭建
    Linux下redis搭建与配置
    iptables-nat实现反向代理功能
    iptables防火墙规则的添加、删除、保存
    [Python]-tools
    [Python]-Game
    .[Linux]-部署Nagios监控
    [HTML]-web前端
    [Linux]-部署Zabbix监控
  • 原文地址:https://www.cnblogs.com/hammerc/p/4026243.html
Copyright © 2011-2022 走看看