【C++入门】(十三)开发高级指针

1. 如何在堆中创建对象?

1.1 在堆中创建对象

  1. 定义了类型 Cat 后,便可声明一个指向这种对象的指针,并在堆中实例化一个 Cat 对象,就像在栈中实例化一样

    Cat *pCat = new Cat;
    ​
    // 这将调用默认构造函数 —— 不接受任何参数的构造函数
    // 每当在堆或栈中创建对象时,都将调用构造函数

     

  1. 为什么要在堆中声明对象?

    函数返回后,在堆中声明的对象依然存在。这种对象还是动态的;此外,在堆中声明的对象可用来创建复杂的数据结构

1.2 删除对象

  1. 对指向堆中对象的指针调用 delete 时,将调用对象的析构函数,然后释放内存。这让类有机会执行清理工作,就像销毁栈中的对象一样

    delete pCat;
    复制代码
    #include <iostream>
    using namespace std;
    ​
    class SimpleCat
    {
    public:
        SimpleCat();
        ~SimpleCat();
    private:
        int itsAge;
    };
    ​
    SimpleCat::SimpleCat()
    {
        cout << "调用构造函数SimpleCat" << endl;
        itsAge = 1;
    }
    ​
    SimpleCat::~SimpleCat()
    {
        cout << "调用析构函数~SimpleCat" << endl;
    }
    ​
    int main()
    {
        cout << "1. 创建一个名为 Frisky 的 SimpleCat类型对象" << endl;
        SimpleCat Frisky;
    ​
        cout << "2. 在堆中new一个SimpleCat对象,并让指针pRags指向它" << endl;
        SimpleCat* pRags = new SimpleCat;
    ​
        cout << "3. 删除指针 pRags" << endl;
        delete pRags;
    ​
        cout << "4. 函数结束时,Frisky不再在作用域内" << endl;
        return 0;
    }
    ​
    //1. 创建一个名为 Frisky 的 SimpleCat类型对象
    //调用构造函数SimpleCat
    //2. 在堆中new一个SimpleCat对象,并让指针pRags指向它
    //调用构造函数SimpleCat
    //3. 删除指针 pRags
    //调用析构函数~SimpleCat
    //4. 函数结束时,Frisky不再在作用域内
    //调用析构函数~SimpleCat
    复制代码

  1. 如果程序员没有显性地执行 delete 命令,对象将在不再在作用域时被删除(调用析构函数)

    如果对象是在 main() 中创建的,且程序员没有显性地删除它,则在 main() 结束后,将调用析构函数

 

2. 如何高效地使用指针?

2.1 使用指针访问数据成员

  1. 对于在栈中创建的 Cat 对象,使用句点运算符 . 来访问其成员数据和成员函数

    (*pRags).GetAge();
    ​
    //要访问堆中 Cat 对象,必须对指针解除引用,并对指针指向的对象使用句点运算符
    // (*pRags) 用括号括起来,以确保对pRags解引用后再访问GetAge()
  2. C++还提供一种简洁的间接访问运算符 -> 指向运算符

    pRags->GetAge();
    
    

2.2 堆中的数据成员

  1. 类可能有一个或多个数据成员为指针,并指向堆中的对象。

    可在构造函数或成员函数中分配内存,并在析构函数中释放内存

    复制代码
    #include <iostream>class SimpleCat
    {
    public:
        SimpleCat();
        ~SimpleCat();
    ​
    private:
        int* itsAge;
        int* itsWeight;
    };
    ​
    SimpleCat::SimpleCat()
    {
    ​
    }
    ​
    SimpleCat::~SimpleCat()  //2. 需要自己写析构函数,否则会造成内存泄露
    {
        delete itsAge;
        delete itsWeight;
    }
    ​
    int main()
    {
        SimpleCat* Frisky = new SimpleCat;
    ​
        delete Frisky;  //1. delete只删除指向堆内存的指针,而不会删除堆中的内容
        return 0;
    }
    复制代码
     

 

2.3 this指针

  1. 每个类成员函数都有一个隐藏的参数 —— this指针 ,它指向用于调用函数的对象

    (通常只是调用函数并设置成员变量的情况下,并不需要this指针,偶尔需要访问对象本身时,this指针将很有用)

    复制代码
    class Rectangle
    {
    public:
        Rectangle();
        ~Rectangle();
      //显示的使用了 this指针 来访问 Rectangle对象 的成员变量,没啥软用
        void SetLength(int length) { this->Length = length; }
        int GetLength() const { return this->Length; }
    ​
    private:
        int Length;
    };
     //不用管 this指针的创建和删除,编译器会负责善后
    复制代码
    
    

2.4 悬摆指针

  1. 悬摆指针 / 野指针 / 迷失指针 是bug之源(之一)

  2. 对指针调用 delete(从而释放它指向的内存)后,如果没有重新赋值就使用,将导致悬摆指针

  3. 对指针调用 delete 后,千万不要使用它。该指针仍指向原来的内存区域(但编译器可能在这里存储了其他数据),使用该指针可能导致程序崩溃。出于安全考虑,删除指针后,应将其设为nullptr

 

2.5 const指针和 const成员函数

  1. const int *p1; 指针指向的对象是常量

    int * const p2; 指针本身是常量

    const int *p1;
    ​
    // p1 是指向整型常量的指针,使用该指针 不能修改它指向的值
    // 不能写 *p1 = 5; 这样的代码
    int * const p2;
    ​
    // p2 是指向整型的常量指针,使用该指针 可修改它指向的整型变量,但不能指向其他变量,不能给常量指针重新赋值
    // 不能写 *p2 = &x; 这样的代码
    const int * const p3;
    ​
    // p3 是指向整型常量的常量指针,使用该指针 不能修改它指向的值,也不能让它指向其他变量

     

 

  1. const 常量成员函数

    复制代码
    class Rectangle
    {
    public:
        //void SetLength(int length) const { itsLength = length; }  //报错,常量成员函数不可修改
        int GetLength() const { return itsLength; }
    ​
    private:
        int itsLength;
        int itsWidth;
    };
    复制代码

     

  1. 如果声明了一个指向常量对象的指针,那么使用该指针只能调用常量函数

    复制代码
    class Rectangle
    {
    public:
        int func1() const { return itsLength; }  //const常量函数
        int func2()       { return itsLength; }
    ​
    private:
        int itsLength = 66;
    };
    ​
    int main()
    {
        //如果声明了一个指向常量对象的指针,那么使用该指针只能调用常量函数
        const Rectangle* p2 = new Rectangle;
    ​
        cout << "指向常量对象的指针p2,只能调用常量函数"<< p2->func1() << endl;
        //cout << "指向常量对象的指针p2,只能调用常量函数"<< p2->func2() << endl;
        //对象含有与成员 函数 "Rectangle::func2" 不兼容的类型限定符   
    return 0;
    }​
    复制代码
    
    
  2. 将对象声明为常量时,实际上是将 this 声明为指向常量对象的指针。

    常量 this指针 只能用于调用常量成员函数

 

 

3. 使用指针时如何避免内存问题?

  1. 指针定义后要初始化,没有指向时指向NULL;

  2. 指针赋值时一定要保证类型匹配

    由于指针类型确定指针所指向对象的类型,因此初始化或赋值时必须保证类型匹配;

  3. 两个指针最好不要指向同一块内存,一个指针的释放会导致另一个指针成为悬垂指针,造成不堪设想的后果;

  4. 释放指针内存后要将该指针置空;

  5. 指针分配成功后才可以使用,要走注意分配后的大小,不要越界。

 

 

4.总结

  1. 指针可指向整型等简单数据类型,也可以指向对象

  2. 可在堆中创建对象,并将其删除(可声明指向类的对象的指针,并在堆中实例化对象)

  3. 类的数据成员可以是指向堆中对象的指针

  4. 可在类的构造函数或其他函数中分配内存,并在析构函数中将其释放

posted @   哟吼--小文文公主  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示