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

智能指针的使用

#include <iostream>
#include <memory> // 智能指针的头文件引入
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

智能指针循环依赖问题

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

#include <iostream>
#include <memory> // 智能指针的头文件引入
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> 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

手写智能指针

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

#include <iostream>
#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;
}
#include <iostream>
#include <memory> // 智能指针的头文件引入
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;
}//弹栈会调用析构函数

四种类型转换

const_cast

const修饰的都可以转换

#include <iostream>
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;
}

static_cast

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

#include <iostream>
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;
}

dynmic_cast

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

#include <iostream>
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;
}

reinterpreet_cast

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

#include <iostream>
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;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值