• C++智能指针与类型转换


    智能指针的使用

    #include 
    #include  // 智能指针的头文件引入
    using namespace std;
    
    class Person{
    public:
    	~Person(){
    	cout << "Person 析构函数" << endl;}
    };
    
    int mian(){
    	Person * person1 = new Person();//堆区开辟
    	//以前 delete person1; 
    	// 现在:
    	shared_ptr<Person> sharedPtr1(person1);// 智能指针帮你释放堆区开辟的--》Person析构函数
    	
    	Person * person2 = new Person();
    	//sharedPtr2 是在栈区开辟的,每添加一个元素 +1 引用计数
    	shared_ptr<Person> sharedPtr2(person2);
    	return 0;
    }//main函数弹栈会释放所有的栈成员, sharedPtr1 sharedPtr2 执行对应的析构函数-1
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    智能指针循环依赖问题

    智能指针有循环依赖的问题,要用就用好,不要用的复杂。

    #include 
    #include  // 智能指针的头文件引入
    using namespace std;
    
    // 先声明,让Person1能直接找到Person2,他们相互拥有,函数只能找到在自己之前声明的函数
    class Person2; 
    
    class Person1{
    public:
    shared_ptr<Person2> person2;
    	~Person1(){
    	cout << "Person1 析构函数" << endl;}
    };
    
    class Person2{
    public:
    shared_ptr<Person1> person1;
    	~Person2(){
    	cout << "Person2 析构函数" << endl;}
    };
    
    int mian(){
    	Person1 * person1 = new Person1();
    	Person2 * person2 = new Person2();
    	shared_ptr<Person> sharedPtr1(person1); // + 1 计数
    	shared_ptr<Person> sharedPtr2(person2);// + 1 计数
    	cout << "前 sharedPtr1计数是:" << sharedPtr1.use_conut() << endl;
    	cout << "后 sharedPtr2计数是:" << sharedPtr2.use_conut() << endl;
    	// 循环依赖 强引用导致泄露,使用weak_ptr person2则不会出现该问题
    	person1->person2 = sharedPtr2;
    	person2->person1 = sharedPtr1;
    	// 计数变成2
    	cout << "前 sharedPtr1计数是:" << sharedPtr1.use_conut() << endl; 
    	cout << "后 sharedPtr2计数是:" << sharedPtr2.use_conut() << endl;
    	
    	return 0;
    }//main函数弹栈会释放所有的栈成员, sharedPtr1 sharedPtr2 执行对应的析构函数-1
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    手写智能指针

    独占式智能指针,用得比较少,源码里面找了很多都没看到,主要还是shared_ptr

    #include 
    #pragma once
    
    using namespace std;
    
    template<typename T>
    class Ptr{
    private:
    	T * object;// 用于指向管理的对象
    	int * count;
    public:
    	Ptr(){
    		count = new int(1);
    		object = 0;
    	}
    	Ptr(T * t): Object(T){
    		// 只要你传入对象,那么引用计数为1
    		conut = new int(1);// new 的对象必须是指针接收,new是为了后面操作方便
    	}
    	~Ptr(){
    		// 引用计数减1,为0可以释放对象
    		if (--(*count) == 0) {
    			if (object){
    				delete object;
    			}
    			// 归零
    			delete count;
    			object = 0;
    			count = 0;
    		}
    	}
    	Ptr(const Ptr<T> & p){
    		cout << "拷贝构造函数" << endl;
    		// ptr2 = ptr1
    		++(*p.count);
    		// 当前对象已经被赋值过的情况,再次被赋值,先清空自己。
    		if (--(*count) == 0) {
    			if (object){
    				delete object;
    			}
    			// 归零
    			delete count;
    			object = 0;
    			count = 0;
    		}
    		
    		object = p.object;
    		count = p.count; 
    	}
    	// 自定义 = 号运算符重载
    	Ptr<T> & operator = (const Ptr<T> & p) {
    		cout << "= 号运算符重载" << endl;
    		++(*p.count);
    		// 当前对象已经被赋值过的情况,再次被赋值,先清空自己。
    		if (--(*count) == 0) {
    			if (object){
    				delete object;
    			}
    			// 归零
    			delete count;
    			object = 0;
    			count = 0;
    		}
    		
    		object = p.object;
    		count = p.count; 
    		return *this;
    	}
    
    	int use_count(){
    		return *this->count;
    	}
    };
    
    class Person{}; 
    
    int mian(){
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    #include 
    #include  // 智能指针的头文件引入
    using namespace std;
    
    
    int mian(){
    	Person * person1 = new Person();
    	Person * person2 = new Person();
    	// 第一种情况
    	Ptr<Person> ptr; // 给自己引用计数 +1 
    	// 第二种情况
    	Ptr<Person> ptr1(person1);// 引用计数 +1 
    /**
    按照正常逻辑:ptr1强引用指向person1,ptr2强引用指向ptr1,
    ptr2 = ptr1; 执行拷贝构造函数是我们自己定义的
    ptr2也持有了person,因为持有ptr1没有意义,我们的目的是管理对象
    person1被ptr1和ptr2都持有了,ptr2计数加1变成2,那么弹栈的时候只有ptr1去销毁person
    ptr2是不会销毁的,就不会造成二次重复执行销毁代码
    */
    	// 第三种情况 
    	Ptr<Person> ptr2 = ptr1; // 直接调用拷贝构造函数,不会调用构造函数
    	//注意调用默认无参数构造
    	Ptr<Person> ptr3;
    	// 这种调用的是默认的拷贝函数不是我们自定义的,所以我们要进行=号运算符重载
    	ptr3 = ptr1; 
    	// 第四种情况
    	ptr<Person> ptr4(Person);
    	ptr<Person> ptr5(Person);
    	// ptr4先清空自己,要不然原来的person会成为野对象
    	ptr4 = ptr5;
    
    	return 0;
    }//弹栈会调用析构函数
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    四种类型转换

    const_cast

    const修饰的都可以转换

    #include 
    using namespace std;
    
    class Person{
    public:
    	string name = "default";
    };
    
    int mian(){
    	const Person * p1 = new Person();
    	//p1->name = "aa"; 常量指针 ,不能修改值
    	Person * p2 = const_cast<Person *>(p1);//将常量指针改成非常量,p2是正常的对象
    	p2->name = "aaa";//修改成功
    	//它实际上多了一个对象p2指向的内存地址跟p1是一样的,p1不能修改,但是p2能改啊!
    	cout << p1->name << endl;//输出aaa
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    static_cast

    指针相关的(包括子父类)都可以转换

    #include 
    using namespace std;
    
    class Father{
    public:
    	void show(){}
    };
    
    class Son : public Father{
    public:
    	void show(){}
    };
    
    int mian(){
    	int n = 88;
    	void * pVoid = &n;
    	int * number = static_cast<int *>(pVoid);
    	cout << *number << endl;// 88 
    
    	Father * father = new Father;
    	father->show();
    	// static_cast 静态转换看左边(编译器确认)
    	Son * son = static_cast<Son *>(father);
    	son->show(); //son的show输出了
    	delete father;// 回收规则,谁new 就回收 谁
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    dynmic_cast

    动态转换:子父类多态 运行期转换

    #include 
    using namespace std;
    
    class Father{
    public:
    	// 动态转换必须让父类成为虚函数
    	virtual void show(){}
    };
    
    class Son : public Father{
    public:
    	void show(){}
    };
    
    int mian(){
    	// 动态转换,在运行期,new Father();已经成定局,所以肯定失败
    	Father * father = new Father();
    	//Father * father = new Son;将上面的代码换成这行代码则就可以,因为: new Son
    	Son * son = dynmic_cast<son *>(father);
    	// 动态转换是有返回值的, null 转换失败
    	if (son) { // != null
    		cout << "成功" << endl;
    		son->show(); 
    	}
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    reinterpreet_cast

    强制转换,比static_cast静态转换强大,静态转换能做的事它都能做。

    #include 
    using namespace std;
    
    class Player{
    public:
    	void show(){}
    };
    
    int mian(){
    	Player * player = new Player;
    	long player1 = reinterpreet_cast<long>(player); // 把对象变成数值
    	// 通过数值变成对象
    	Player * player2 = reinterpreet_cast<Player *>(player1);
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    安装typescript环境并开启VSCode自动监视编译ts文件为js文件
    【OS基础】符合AUTOSAR标准的RTAOS-Alarms详解
    linux内网服务器设置全局代理和yum代理
    多个文件合成一个bin文件(将uboot/kernel/rootfs合成一个bin文件烧录)(UBin工具下载)
    功能农业育种 国稻种芯-何登骥:广西稻作文化园农业大健康
    【C++报错】error C2143:语法错误:缺少“ : ”(在“<” 的前面)[ 相互引用问题 ]
    Vue(九)——页面路由(1)
    蓝桥杯算法训练-共线
    【Linux】Linux编译器-gcc/g++使用
    【Python基础】if __name__ == ‘__main__‘:和assert函数
  • 原文地址:https://blog.csdn.net/qq_34606099/article/details/126392258