C++操作符重载+、-、*、/、[]、()、<<、>>、=、new、delete、&&、||、++、--、+=、强制转换重载

本文详细介绍了C++中的操作符重载概念及其应用场景,包括算术操作符、比较操作符、输入输出操作符等的重载实现,并通过实例说明了如何正确使用这些重载操作符。

内容汇总

#include <iostream>
using namespace std;

class A {
	//友元函数,类外函数访问私有变量
	//friend A operator-(const A& c1, const A& c2);
	//friend A& operator+=(A& c1, const A& c2);
	//friend A& operator++(A& c);//++a
	//friend A operator++(A& c, int);//a++
	//重载<<和>>最好在类外
	friend ostream& operator<<(ostream& os, A& c);
	friend istream& operator>>(istream& is, A& c);
private:
	int a;
	int b;
public:
	A(int a = 0, int b = 0) :a(a), b(b) {}
	void print() {
		cout << a << "+" << b << endl;
	}
	//类内重载-
	A operator-(const A& another) {
		A c((this->a) - another.a, (this->b) - another.b);
		return c;
	}
	//类内重载+
	A operator+(const A& another) {
		A c((this->a) + another.a, (this->b) + another.b);
		return c;
	}
	//类内重载+=
	A& operator+=(const A& another) {
		(*this).a += another.a;
		(*this).b += another.b;
		return (*this);
	}
	//类内重载++a
	A& operator++() {
		(*this).a++;
		(*this).b++;
		return (*this);
	}
	//类内重载a++,需要默认参数,此处不需要返回&
	A operator++(int) {
		A tmp = (*this);
		(*this).a++;
		(*this).b++;
		return tmp;
	}
	//类内重载=
	A& operator=(const A& c) {
		if (this == &c)
			return (*this);
		(*this).a = c.a;
		(*this).b = c.b;
		return (*this);
	}
};
////类外重载-
//A operator-(const A& c1, const A& c2) {
//	A c(c1.a - c2.a, c1.b - c2.b);
//	return c;
//}
////类外重载+
//A operator-(const A& c1, const A& c2) {
//	A c(c1.a + c2.a, c1.b + c2.b);
//	return c;
//}
////类外重载+=
//A& operator+=(A& c1,const A& c2) {
//	c1.a += c2.a;
//	c1.b += c2.b;
//	return c1;
//}
////类外重载++a
//A& operator++(A& c) {
//	c.a++;
//	c.b++;
//	return c;
//}
////类外重载a++
//A operator++(A& c,int) {
//	A tmp = c;
//	c.a++;
//	c.b++;
//	return tmp;
//}
//<<和>>最好类外重载
ostream& operator<<(ostream& os, A& c) {
	os << c.a << '+' << c.b;
	return os;
}
istream& operator>>(istream& is, A& c) {
	is >> c.a >> c.b;
	return is;
}
int main() {
	A c1(1, 1), c2(2, 2), c3;
	cin >> c3;
	cout << c3 << endl;
}

一.来源

假设,现在有类A:

class A {
public:
	A(int a) {
		this->a = a;
	}
private:
	int a;
};

定义:

A a1(1), a2(2);

现在我想直接执行两个类的相加a1+a2,但是C++没有这种方法,所以引出操作符重载。

二.实现

现在实现两个虚数相加:(1+2i)+(3+4i).
先看2种普通实现方法:
方法一:

class Complex {
	friend Complex complexadd(Complex& c1, Complex& c2);//定义友元函数
public:
	Complex(int a,int b) {
		this->a = a;
		this->b = b;
	}
	void printComplex() {
		cout << "(" << this->a << "," << this->b << "i)" << endl;
	}
private:
	int a;//实数
	int b;//虚数
};
//相加
Complex complexadd(Complex& c1, Complex& c2) {
	Complex c3(c1.a + c2.a, c1.b + c2.b);
	return c3;
}
int main() {
	Complex a1(1,2), a2(3,4);
	a1.printComplex();
	a2.printComplex();
	Complex c3 = complexadd(a1, a2);
	c3.printComplex();
}

方法二:

class Complex {
public:
	Complex(int a,int b) {
		this->a = a;
		this->b = b;
	}
	void printComplex() {
		cout << "(" << this->a << "," << this->b << "i)" << endl;
	}
	Complex addcomplex(const Complex& another) {
		Complex a3(this->a + another.a, this->b + another.b);
		return a3;
	}
private:
	int a;//实数
	int b;//虚数
};
int main() {
	Complex a1(1,2), a2(3,4);
	a1.printComplex();
	a2.printComplex();
	Complex a3=a2.addcomplex(a1);
	a3.printComplex();
}

操作符重载方法:
方法一:操作符重载写在全局

class Complex {
	friend Complex operator+(Complex& a1, Complex& a2);//申明友元函数
public:
	Complex(int a,int b) {
		this->a = a;
		this->b = b;
	}
	void printComplex() {
		cout << "(" << this->a << "," << this->b << "i)" << endl;
	}
private:
	int a;//实数
	int b;//虚数
};
//操作符重载写在全局
Complex operator+(Complex& a1, Complex& a2) {
	Complex a3(a1.a + a2.a, a1.b + a2.b);
	return a3;
}
int main() {
	Complex a1(1,2), a2(3,4);
	a1.printComplex();
	a2.printComplex();
	//此处可以直接实现加法!等价于Complex a3 = operator(a1,a2);
	Complex a3 = a1 + a2;
	a3.printComplex();
}

方法二:操作符重载写在局部

class Complex {
public:
	Complex(int a,int b) {
		this->a = a;
		this->b = b;
	}
	void printComplex() {
		cout << "(" << this->a << "," << this->b << "i)" << endl;
	}
	//操作符重载写在局部
	Complex operator+(Complex& another) {
		Complex a3(this->a + another.a, this->b + another.b);
		return a3;
	}
private:
	int a;//实数
	int b;//虚数
};
int main() {
	Complex a1(1,2), a2(3,4);
	a1.printComplex();
	a2.printComplex();
	//此处可以直接实现加法!
	Complex a3 = a1 + a2;
	//等价
	Complex a4 = a1.operator+(a2);
	a3.printComplex();
	a4.printComplex();
}

三.注意事项

1.记住不能重载的,其他都可以重载。

::.
.*?*
sizeoftypeid

2.不能创造重载。例如:a1 666 a2。自己创造一个666运算。
3.重载不能改变运算符的优先级别。

4.重载不能改变运算符的结合性。
5.重载运算符的函数不能有默认参数。
在这里插入图片描述

7.=, ->, [], ()不可以是全局域中的重载(即不能重载为友员函数)

1.重载减号(-)

class A {
	friend A operator-(const A& c1, const A& c2);//申明友元函数
private:
	int a;//实部
	int b;//虚部
public:
	A(int a, int b) {
		this->a = a;
		this->b = b;
	}
	void print() {
		cout << "(" << a << "+" << b << "i)" << endl;
	}
	//操作符重载类内定义
	A operator-(const A& another) {
		A c(this->a - another.a, this->b - another.b);
		return c;
	}
};
//操作符重载外部定义
//A operator-(const A& c1, const A& c2) {
//	A c(c1.a - c2.a, c1.b - c2.b);
//	return c;
//}
int main() {
	A c1(3, 4), c2(1, 2);
	A c = c1 - c2 - c2;
	c.print();
}

2.+=号重载

class A {
	//friend A& operator+=(A& c1, A c2);//友元函数声明
private:
	int a;//实部
	int b;//虚部
public:
	A(int a, int b) {
		this->a = a;
		this->b = b;
	}
	void print() {
		cout << "(" << a << "+" << b << "i)" << endl;
	}
	//"+="操作符重载类内定义
	A &operator+=( A& another) {
		this->a += another.a;
		this->b += another.b;
		return *this;
	}
};
//“+=”操作符重载外部定义
/*A& operator+=(A& c1, A c2) {
	c1.a += c2.a;
	c1.b += c2.b;
	return c1;
}*/
int main() {
	A c1(3, 4), c2(1, 2);
	c1 += c2;
	c1.print();
}

3.++a重载

class A {
	//friend A& operator++(A& c);//友元函数声明
private:
	int a;//实部
	int b;//虚部
public:
	A(int a, int b) {
		this->a = a;
		this->b = b;
	}
	void print() {
		cout << "(" << a << "+" << b << "i)" << endl;
	}
	//"++"操作符重载类内定义
	A & operator++( ) {
		this->a++;
		this->b++;
		return *this;
	}
};
//“++”操作符重载外部定义
/*A& operator++(A& c) {
	c.a++;
	c.b++;
	return c;
}*/
int main() {
	A c1(3, 4), c2(1, 2);
	++c1;
	c1.print();
}

4.a++重载

这里是C++一个坑,用没有意义的占位参数,标识是后++。

class A {
	//friend A& operator++(A& c,int);//友元函数声明
private:
	int a;//实部
	int b;//虚部
public:
	A(int a, int b) {
		this->a = a;
		this->b = b;
	}
	inline void print() {
		cout << "(" << a << "+" << b << "i)" << endl;
	}
	//"++a"操作符重载类内定义
	A& operator++( ) {
		this->a++;
		this->b++;
		return *this;
	}
	//"a++"操作符重载类内定义
	A  operator++( int ) {//此处不能用const A&,因为temp在函数运行完成后被释放,此处不必返回&
		A temp=*this;//用一个临时变量
		this->a++;
		this->b++;
		/*
		++(*this);//或者直接调用++a,代替上面两步,更爽!
		*/
		return temp;
	}
};
#if 0
//“a++”操作符重载外部定义
A operator++(A& c, int) //int为占位参数,用来标识后++,此处返回值不必为&
{
	A temp=c;
	c.a++; c.b++;
	return temp;
}
#endif // 0
int main() {
	A c1(3, 4), c2(1, 2);
	c1++;
	c1.print();
}

5.为什么这里都用&引用

A& operator++(A& c)

如果不用引用,就无法实现连加,目的还是为了防止函数执行完后返回的匿名对象被释放掉,后面就无法访问其值。

为什么a++,不必返回引用呢?因为即使返回引用,得到的值,也只是第一次++后的值。因为后++返回的是temp,不是*this。
前++返回当前对象,离开这个函数后,当前对象依然存在,因此可以返回引用;后++返回是一个局部对象,离开函数就被消亡,因此不能返回引用!
看下面例子也能明白。
在这里插入图片描述

6.<<左移操作符重载

作用:实现直接输出类中变量的值。
在这里插入图片描述
查看cout类型:鼠标放在cout上,右键点击转到定义。
在这里插入图片描述
实现:

class A {
	//friend ostream& operator<<(ostream& os, A& t);//友元函数申明
private:
	int a;
	int b;
public:
	A(int a, int b) {
		this->a = a;
		this->b = b;
	}
	//类内重载
	ostream& operator<<(ostream& os) {
		os << "a=" << this->a << ",b=" << this->b << endl;
		return os;
	}
};
//重载外部定义
/*ostream& operator<<(ostream& os, A& t) {
	os << "a=" << t.a << ",b=" << t.b << endl;
	return os;
}*/
int main(int argc, char** argv)
{
	A t1(1, 2);
	t1 << cout;//类内重载,写法很奇怪
	//cout << t1 << endl;//类外重载
}

注意:为什么ostream& operator<<(ostream& os, A& t),返回是ostream。

	int a = 1;
	int b = 2;
	int c = 3;
	cout << a << b << c << endl;
因为cout<<a,返回值是cout,然后才能继续输出后面cout<<b,cout<<c<<endl;

7.>>右移操作符重载

class A {
	friend istream& operator>>(istream& in, A& t1);//友元函数申明
private:
	int a;
	int b;
public:
	A() {
		this->a = 0;
		this->b = 0;
	}
	~A() {
		cout << "a=" << this->a << ",b=" << b << endl;
	}
};
//重载外部定义
istream& operator>>(istream& is, A& t1) {
	is >> t1.a;
	is >> t1.b;
	return is;
}
int main(int argc, char** argv)
{
	A t1;
	cin >> t1;
}

8.=操作符重载

class Student
{
public:
	Student() {
		this->id = 0;
		this->name = nullptr;
	}
	//拷贝构造
	Student(int id, char* name) {
		this->id = id;
		//对*name一定要申请空间,否则浅拷贝,数据不安全。
		int len = strlen(name);//判断字符数组长度,用strlen,不是size、sizeof
		this->name = new char[len+1];//+1是为了预留一个'\0'
		strcpy_s(this->name,len+1, name);
	}
	//深拷贝构造
	Student(const Student& s) {
		this->id = s.id;
		this->name = new char[strlen(s.name)+1];
		strcpy_s(this->name, strlen(s.name) + 1,s.name);
	}
	~Student() {
		if (this->name != nullptr) {
			delete[] this->name;
			this->name = nullptr;
			this->id = 0;
		}
	}
	void print() {
		cout << "id=" << this->id << ",name=" << this->name << endl;
	}
	//"="操作符重载
	Student& operator=(Student& s) {
		//1.s=s,直接返回本身。
		if (this == &s)
			return *this;
		//2.先将原来空间释放掉
		if (this->name != nullptr) {
			delete[] this->name;
			this->name = nullptr;
			this->id = 0;
		}
		//3.执行深拷贝
		this->id = s.id;
		this->name = new char[strlen(s.name) + 1];
		strcpy_s(this->name, strlen(s.name) + 1, s.name);
		return *this;
	}
private:
	int id;
	char* name;
};
int main() {
	char name1[64] = "abc";
	Student s1(1, name1);
	//在这里等号实际上为拷贝构造,等价于s2(s1);
	Student s2=s1;
	s2.print();
	char name2[64] = "def";
	//“=”操作符重载
	Student s3(2, name2);
	s2 = s3;
	s2.print();
}

9.重载小括号()

class Sqr
{
public:
	Sqr(int a) {
		this->a = a;
	}
	//重载小括号“()”
	int operator()(int b) {
		return b * b;
	}
	int operator()(int b, int c) {
		return b * c;
	}
private:
	int a;
};
int main() {
	Sqr s1(1);
	//s1(2)将对象当成一个普通函数来调用,称这种对象是仿函数或伪函数
	int value1=s1(2);
	cout << value1 << endl;
	int value2 = s1(3, 4);
}

10.new和delete重载

void和void之间没有任何关系,void是一个万能指针。
使用new可以触发类的构造函数,使用delete会触发类的析构函数。

class A
{
public:
	A(int a) {
		cout << "调用了有参构造函数" << endl;
		this->a = a;
	}
	void print() {
		cout << "a=" << a << endl;
	}
	//new操作符重载,void*返回一个万能指针,size_t是申请内存大小
	//重载的new操作符,依然会触发对象的构造函数
	void* operator new(size_t size) {
		cout << "重载了new操作符" << endl;
		return malloc(size);
	}
	void operator delete(void* p) {
		cout << "重载了delete操作符" << endl;
		if (p != nullptr) {
			free(p);
			p = nullptr;
		}
	}
	~A() {
		cout << "触发了析构函数" << endl;
	}
private:
	int a;
};
int main() {
	//等价于ap->operator new(sizeof(A));这里的10会触发构造函数
	A* ap = new A(10);
	ap->print();
	delete ap;
}

结果:
在这里插入图片描述

11.[ ]重载

class A
{
public:
	A() {
		this->a = 0;
	}
	A(int a) {
		cout << "调用了有参构造函数" << endl;
		this->a = a;
	}
	void print() {
		cout << "a=" << a << endl;
	}
	//new操作符重载,void*返回一个万能指针,size_t是申请内存大小
	//重载的new操作符,依然会触发对象的构造函数
	void* operator new[](size_t size) {
		cout << "重载了new[]操作符" << endl;
		return malloc(size);
	}
	void operator delete[](void* p) {
		cout << "重载了delete操作符" << endl;
		if (p != nullptr) {
			free(p);
			p = nullptr;
		}
	}
	~A() {
		cout << "触发了析构函数" << endl;
	}
private:
	int a;
};
int main() {
	//触发无参构造,实际上申请空间大小sizeof(A)*10
	A* ap = new A[10];
	ap->print();
	//触发10次void operator delete[](void* p)
	delete[] ap;
}

结果:
在这里插入图片描述

12.&&和| |重载(不建议重载这两个)

首先看以下代码:

int a = 0;
	if (a && (a = 10)) {//在这里a=10被短路了,没有执行。
	}
	cout << "a=" << a << endl;

结果:
在这里插入图片描述
实现&&重载代码:

class Test {
private:
	int value;
public:
	Test(int value) {
		this->value = value;
	}
	//重载&&
	bool operator&&(Test&  another) {
		cout << "执行了&&操作符重载!" << endl;
		if ( this->value&&another.value)
		{
			return true;
		}
		else {
			return false;
		}
	}
};
int main() {
	Test t1(10), t2(20);
	if (t1 && t2) {//t1.operator&&(t2)
		cout << "t1和t2都不为空" << endl;
	}
	else {
		cout << "t1或t2为空" << endl;
	}
}

结果:
在这里插入图片描述

class Test {
private:
	int value;
public:
	Test(int value) {
		this->value = value;
	}
	/*~Test() {
		cout << "value=" << value << endl;
	}*/
	//重载&&
	void print() {
		cout << "value=" << value << endl;
	}
	bool operator||(Test&  another) {
		cout << "执行了&&操作符重载!" << endl;
		if ( this->value||another.value)
		{
			return true;
		}
		else {
			return false;
		}
	}
	//重载+
	Test& operator+(Test& another) {
		this->value += another.value;
		return *this;
	}
};
int main() {
	Test t1(0), t2(20);
	if (t1 ||  t2) {
		cout << "t1或t2不为0" << endl;
	}
	else {
		cout << "t1和t2都为0!" << endl;
	}
}

结果:
在这里插入图片描述

13.强制类型转换

class boolean {
	//输出,false输出false,true输出true
	friend ostream& operator<<(ostream& os, const boolean& b);
	friend istream& operator>>(istream& is, boolean& b);
private:
	bool data;
public:
	boolean(const bool d = false) :data(d) {}
	~boolean() {}
	//强制类型转换:实现(int)boolean或int(boolean)输出1或0
	operator int() const { return (data ? 1 : 0); }
};
#include "boolean.h"
ostream& operator<<(ostream& os, const boolean& b) {
	os << (b.data == true ? "true" : "false");
	return os;
}
istream& operator>>(istream& is, boolean& b) {
	string tmp;
	is >> tmp;
	b.data = (tmp == "true" ? true : false);
	return is;
}
int main() {
	boolean b(true);
	cout << (int)b << endl;//此处使用强制类型转换
	cout << int(b) << endl;//同上
}
}
namespace DeepMapAcad { // 前向声明一个模板类 observer_ptr,用于处理对对象的指针 template<typename T> class observer_ptr; // 用于处理引用计数对象的智能指针。 template<class T> class rhref_ptr { public: typedef T element_type; rhref_ptr() : _ptr(0) { } rhref_ptr(T* ptr) : _ptr(ptr) { if (_ptr) _ptr->ref(); } /// <summary> /// 用于创建一个新的 rhref_ptr 对象,该对象是另一个 rhref_ptr 对象的副本 /// </summary> /// <param name="rp">指向要拷贝的 rhref_ptr 对象。通过使用常量引用,可以避免不必要的拷贝,同时确保不会修改原始对象</param> rhref_ptr(const rhref_ptr& rp) : _ptr(rp._ptr) { // 检查 _ptr 是否为非空指针 if (_ptr) // 增加所指向对象的引用计数 // 这是引用计数智能指针的核心机制, // 确保在多个 rhref_ptr 对象指向同一个对象时, // 对象的引用计数会相应增加,从而避免对象被过早销毁 _ptr->ref(); } /// <summary> /// 模板拷贝构造函数 /// </summary> /// <typeparam name="Other">允许传入不同模板参数类型的 rhref_ptr 对象</typeparam> /// <param name="rp"></param> template<class Other> rhref_ptr(const rhref_ptr<Other>& rp) : _ptr(rp._ptr) // 即让两个 rhref_ptr 对象指向同一个底层指针 { if (_ptr) _ptr->ref(); } /// <summary> /// 从 observer_ptr<T> 对象创建一个 rhref_ptr 对象 /// </summary> /// <param name="optr">通常是一个弱引用指针,不拥有对象的所有权,只观察对象的生命周期</param> rhref_ptr(observer_ptr<T>& optr) : _ptr(0) { // 调用 observer_ptr 对象的 lock 方法,并将当前 rhref_ptr 对象的引用作为参数传递给它 // lock 方法的作用通常是尝试将弱引用转换为强引用。 // 如果 observer_ptr 所观察的对象仍然存在,lock 方法会使 rhref_ptr 指向该对象, // 并可能增加对象的引用计数; // 如果对象已经被销毁,lock 方法可能会保持 rhref_ptr 为 nullptr optr.lock(*this); } /// <summary> /// 管理所指向对象的引用计数,并在必要时释放对象的内存 /// </summary> ~rhref_ptr() { if (_ptr) _ptr->unref(); _ptr = 0; } /// <summary> /// /// </summary> /// <param name="rp"></param> /// <returns></returns> rhref_ptr& operator = (const rhref_ptr& rp) { // 通常是将 rp 对象的状态复制到当前对象,可能涉及到引用计数的更新、指针的复制等操作 assign(rp); // 返回当前对象的引用。这是为了支持连续赋值操作,例如 a = b = c return *this; } template<class Other> rhref_ptr& operator = (const rhref_ptr<Other>& rp) { // 将 rp 的状态复制到当前对象,最后返回当前对象的引用,以支持连续赋值操作 assign(rp); return *this; } /// <summary> /// 重载的赋值运算符函数,其功能是将一个普通指针 T* 赋值给 rhref_ptr 对象 /// inline 关键字表明该函数可能会被编译器内联展开,以减少函数调用的开销。 /// 函数返回 rhref_ptr 对象的引用,这使得该赋值操作可以支持链式赋值,例如 a = b = c /// </summary> /// <param name="ptr"></param> /// <returns></returns> inline rhref_ptr& operator = (T* ptr) { if (_ptr == ptr) return *this; T* tmp_ptr = _ptr; _ptr = ptr; if (_ptr) _ptr->ref(); // unref second to prevent any deletion of any object which might // be referenced by the other object. i.e rp is child of the original _ptr. // 可能需要进行一些资源释放操作,如减少引用计数等 // 这里简单假设直接释放 if (tmp_ptr) tmp_ptr->unref(); return *this; } /// <summary> /// implicit output conversion /// 类型转换运算符重载函数 它允许将 rhref_ptr 类型的对象隐式转换为 T* 类型的指针。 /// 当代码中需要一个 T* 类型的指针, /// 而实际提供的是 rhref_ptr 对象时,编译器会自动调用这个类型转换运算符, /// 将 rhref_ptr 对象转换为 T* 指针 /// </summary> #ifdef OSG_USE_REF_PTR_IMPLICIT_OUTPUT_CONVERSION // implicit output conversion operator T* () const { return _ptr; } #else /// <summary> /// comparison operators for rhref_ptr. /// 比较两个 rhref_ptr 对象是否相等 /// </summary> /// <param name="rp"></param> /// <returns></returns> bool operator == (const rhref_ptr& rp) const { // 通过比较两个 rhref_ptr 对象内部的指针 _ptr 是否相等来判定对象是否相等 return (_ptr == rp._ptr); } /// <summary> /// 用于比较当前类对象内部的指针 _ptr 和传入的指针 ptr 是否指向同一块内存地址。 /// 如果两个指针指向同一块内存地址,函数返回 true;反之,返回 false /// </summary> /// <param name="ptr"></param> /// <returns></returns> bool operator == (const T* ptr) const { return (_ptr == ptr); } /// <summary> /// 重载的 == 运算符函数,并且被声明为 rhref_ptr 类的友元函数。 /// 该函数用于比较一个类型为 T* 的指针 ptr 和 rhref_ptr 类对象 rp 内部的私有指针 _ptr 是否指向同一块内存地址。 /// </summary> /// <param name="ptr"></param> /// <param name="rp"></param> /// <returns>如果两个指针指向同一块内存地址,函数返回 true;反之,返回 false</returns> friend bool operator == (const T* ptr, const rhref_ptr& rp) { return (ptr == rp._ptr); } /// <summary> /// 重载的 != 运算符函数,用于比较两个 rhref_ptr 对象是否不相等。通常,这个函数会基于 rhref_ptr 对象内部的指针成员进行比较。 /// 该函数在需要判断两个 rhref_ptr 对象是否代表不同的资源时非常有用。 /// 例如,在容器中查找特定的 rhref_ptr 对象,或者在进行条件判断时, /// 需要确定两个 rhref_ptr 对象是否指向不同的实体 /// </summary> /// <param name="rp"></param> /// <returns>如果两个 rhref_ptr 对象内部的指针指向不同的内存地址,函数返回 true;反之,如果指向相同的内存地址,则返回 false</returns> bool operator != (const rhref_ptr& rp) const { return (_ptr != rp._ptr); } /// <summary> /// 用于比较该类对象内部的指针 _ptr 与传入的指针 ptr 是否不相等 /// 函数接受一个 const T* 类型的参数 ptr,表示一个指向 T 类型对象的常量指针。 /// const 修饰符表示该函数不会修改调用该函数的对象的状态。 /// 函数体中,通过比较 _ptr 和 ptr 的值来判断它们是否指向不同的内存地址。 /// 在使用标准库容器(如 std::vector、std::list 等)时,如果容器中存储的是自定义类对象, /// 并且需要根据对象内部的指针进行比较和查找操作, /// 重载的 != 运算符可以方便地实现这些功能 /// </summary> /// <param name="ptr"></param> /// <returns>如果 _ptr 和 ptr 指向不同的地址,函数返回 true;否则返回 false</returns> bool operator != (const T* ptr) const { return (_ptr != ptr); } /// <summary> /// 重载的 != 运算符函数,并且它被声明为 rhref_ptr 类的友元函数。 /// 这意味着该函数可以访问 rhref_ptr 类的私有成员 _ptr /// </summary> /// <param name="ptr"></param> /// <param name="rp"></param> /// <returns>比较传入的指针 ptr 和 rhref_ptr 对象 rp 内部的私有指针成员 _ptr 是否不相等。 /// 如果 ptr 和 rp._ptr 指向不同的内存地址,函数返回 true;否则返回 false</returns> friend bool operator != (const T* ptr, const rhref_ptr& rp) { return (ptr != rp._ptr); } /// <summary> /// 重载的小于运算符 < 函数。该函数是 rhref_ptr 类的成员函数, /// 因为它使用了 const 修饰,意味着调用该函数不会修改调用对象的状态 /// </summary> /// <param name="rp">接受一个 const rhref_ptr& 类型的引用 rp 作为参数,用于和当前对象进行比较。</param> /// <returns>函数的核心逻辑是比较当前对象的私有指针成员 _ptr 和传入对象 rp 的私有指针成员 _ptr 的地址大小。如果当前对象的 _ptr 指针地址小于 rp._ptr 的地址,则返回 true;否则返回 false</returns> bool operator < (const rhref_ptr& rp) const { return (_ptr < rp._ptr); } // 安全布尔值 // follows is an implementation of the "safe bool idiom", details can be found at: // “Safe bool idiom” 是一种用于安全地将类对象转换为布尔值的技术 // 在 C++ 中,直接重载 operator bool() 可能会导致意外的隐式转换, // 例如在算术运算中可能会将对象当作整数使用,从而引发难以调试的错误。 // Safe bool idiom 通过将布尔转换操作封装在一个更安全的机制中,避免了这种意外的隐式转换。 // 其核心思想是利用指向成员函数的指针, // 因为指向成员函数的指针只能在布尔上下文中使用,而不能用于其他算术或比较运算, // 从而确保了转换的安全性 // http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool // http://lists.boost.org/Archives/boost/2003/09/52856.php private: // 定义了一个类型别名 unspecified_bool_type, // 它是一个指向 rhref_ptr 类成员的指针类型, // 该成员的类型是 T*。在安全布尔惯用法的上下文中, // unspecified_bool_type 通常用于实现类的布尔转换运算符, // 以避免隐式转换带来的意外行为 typedef T* rhref_ptr::* unspecified_bool_type; public: // safe bool conversion /// <summary> /// 型转换运算符函数。此函数的作用是将 rhref_ptr 对象隐式转换为 unspecified_bool_type 类型 /// 类型转换运算符用于在布尔语境下判断对象是否有效 /// </summary> operator unspecified_bool_type() const { // valid()判断当前对象是否处于有效状态 return valid() ? &rhref_ptr::_ptr : 0; } #endif /// <summary> /// 重载的解引用运算符。在 C++ 中,当使用 * 运算符作用于对象时,会调用这个重载函数。 /// 其主要作用是模拟指针的解引用操作,使得对象的使用方式更像指针。 /// 例如, /// 若有一个自定义的智能指针类, 通过重载该运算符, /// 就可以像使用普通指针一样使用该智能指针类的对象来访问其所指向的对象 /// </summary> /// <returns></returns> T& operator*() const { #ifdef OSG_USE_REF_PTR_SAFE_DEREFERENCE if (!_ptr) { // pointer is invalid, so throw an exception throw std::runtime_error(std::string("could not dereference invalid osg pointer ") + std::string(typeid(T).name())); } #endif return *_ptr; } /// <summary> /// 对箭头运算符 -> 的重载,其作用是让对象的使用方式更像指针。 /// 通过重载该运算符,对象可以像普通指针一样使用 -> 来访问其所指向对象的成员。 /// 结合之前的 * 运算符重载函数,使得该对象在使用上与普通指针几乎没有区别 /// 首先会检查指针 _ptr 是否为空。如果为空,会抛出一个 std::runtime_error 异常, /// 提示“could not call invalid osg pointer ” 并附带类型信息, /// 避免对空指针进行操作导致的未定义行为。如果指针不为空,则直接返回该指针 /// </summary> /// <returns></returns> T* operator->() const { #ifdef OSG_USE_REF_PTR_SAFE_DEREFERENCE if (!_ptr) { // pointer is invalid, so throw an exception. throw std::runtime_error(std::string("could not call invalid osg pointer ") + std::string(typeid(T).name())); } #endif return _ptr; } /// <summary> /// 作用是返回智能指针内部所管理的原始指针 _ptr。 /// 该函数是一个常量成员函数,意味着在调用时不会修改对象的状态。 /// 通过这个函数,可以直接获取到智能指针背后的原始指针,从而可以在需要使用原始指针的场景中使用。 /// 例如,在与一些只接受原始指针的第三方库进行交互时,就可以使用 get() 函数来获取原始指针 /// </summary> /// <returns></returns> T* get() const { return _ptr; } /// <summary> /// 检查智能指针内部的原始指针 _ptr 是否为空指针 /// </summary> /// <returns>如果 _ptr 为空指针(即 _ptr == 0 或 _ptr == nullptr),则返回 true; /// 否则返回 false</returns> bool operator!() const { return _ptr == 0; } // not required /// <summary> /// 用是检查智能指针内部的原始指针 _ptr 是否为非空指针。 /// </summary> /// <returns>如果 _ptr 不是空指针(即 _ptr != 0 或 _ptr != nullptr),则返回 true,表示智能指针指向一个有效的对象;否则返回 false,表示智能指针为空</returns> bool valid() const { return _ptr != 0; } /** release the pointer from ownership by this rhref_ptr<>, decrementing the objects refencedCount() via unref_nodelete() to prevent the Object * object from being deleted even if the reference count goes to zero. Use when using a local rhref_ptr<> to an Object that you want to return * from a function/method via a C pointer, whilst preventing the normal rhref_ptr<> destructor from cleaning up the object. When using release() * you are implicitly expecting other code to take over management of the object, otherwise a memory leak will result. */ /// <summary> /// 用于释放对内部原始指针的所有权。 /// 调用 release 函数后,智能指针不再管理这块内存, /// 它会返回内部的原始指针,并且将自身的内部指针置为 nullptr /// 转移所有权: /// 当需要将智能指针管理的资源转移给其他代码部分时,可以使用 release 函数。 /// 例如,将智能指针管理的资源传递给一个不支持智能指针的旧接口。 /// 手动管理资源:在某些特定场景下,需要手动控制资源的生命周期, /// 此时可以使用 release 函数将资源从智能指针中释放出来,然后手动进行管理 /// </summary> /// <returns></returns> T* release() { T* tmp = _ptr; if (_ptr) _ptr->unref_nodelete(); _ptr = 0; return tmp; } /// <summary> /// 交换两个 rhref_ptr 对象所管理的原始指针。 /// 也就是说,调用 swap 方法后,两个 rhref_ptr 对象会互相持有对方原本管理的资源 /// 资源交换:在某些场景下,需要交换两个智能指针所管理的资源,此时可以使用 swap 方法。 /// 算法实现:在一些算法实现中,可能需要对智能指针进行交换操作, /// 使用 swap 方法可以方便地实现这一需求 /// </summary> /// <param name="rp"></param> void swap(rhref_ptr& rp) { T* tmp = _ptr; _ptr = rp._ptr; rp._ptr = tmp; } private: /// <summary> /// 用于将一个 rhref_ptr 对象的资源赋值给另一个 rhref_ptr 对象 /// </summary> /// <typeparam name="Other"></typeparam> /// <param name="rp"></param> template<class Other> void assign(const rhref_ptr<Other>& rp) { if (_ptr == rp._ptr) return; T* tmp_ptr = _ptr; _ptr = rp._ptr; if (_ptr) _ptr->ref(); // unref second to prevent any deletion of any object which might // be referenced by the other object. i.e rp is child of the // original _ptr. if (tmp_ptr) tmp_ptr->unref(); } // friend 声明用于允许其他类或函数访问当前类的私有成员。 // 在 rhref_ptr 类中,friend 声明可以用于允许特定的类或函数直接访问 _ptr 指针 template<class Other> friend class rhref_ptr; T* _ptr; }; /// <summary> /// 交换两个 rhref_ptr 类型对象的内容 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="rp1"></param> /// <param name="rp2"></param> template<class T> inline void swap(rhref_ptr<T>& rp1, rhref_ptr<T>& rp2) { rp1.swap(rp2); } /// <summary> /// 从 rhref_ptr 类型的对象中提取其所管理的原始指针 /// 让用户可以直接访问 rhref_ptr 内部所存储的原始指针 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="rp"></param> /// <returns></returns> template<class T> inline T* get_pointer(const rhref_ptr<T>& rp) { return rp.get(); } /// <summary> /// 对 rhref_ptr 类型的智能指针进行静态类型转换 /// 用途类似于标准库中的 std::static_pointer_cast, /// 主要用于在不同类型的智能指针之间进行静态类型转换。 /// 在实际编程中,当需要将一个指向某种类型的智能指针转换为指向另一种类型的智能指针时, /// 可以使用这个函数。这种转换通常在继承关系中使用, /// 例如将指向基类的智能指针转换为指向派生类的智能指针(前提是这种转换在逻辑上是安全的),或者反之 /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="Y"></typeparam> /// <param name="rp"></param> /// <returns></returns> template<class T, class Y> inline rhref_ptr<T> static_pointer_cast(const rhref_ptr<Y>& rp) { return static_cast<T*>(rp.get()); } /// <summary> /// 智能指针进行动态类型转换。 /// 模板参数 T 代表转换后的目标类型,Y 代表转换前的原始类型。 /// 函数接收一个 const rhref_ptr<Y>& 类型的参数 rp, /// 也就是一个指向 Y 类型对象的 rhref_ptr 智能指针的常量引用, /// 这保证了函数不会修改传入的 rhref_ptr 对象 /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="Y"></typeparam> /// <param name="rp"></param> /// <returns></returns> template<class T, class Y> inline rhref_ptr<T> dynamic_pointer_cast(const rhref_ptr<Y>& rp) { // 函数内部使用 dynamic_cast<T*>(rp.get()) 进行动态类型转换。 // rp.get() 会调用 rhref_ptr<Y> 类的 get 成员函数, // 返回其所管理的原始指针(类型为 Y*), // 然后使用 dynamic_cast<T*> 将这个 Y* 类型的原始指针尝试转换为 T* 类型的指针。 // dynamic_cast 是 C++ 中的一个类型转换操作符, // 主要用于在继承体系中进行安全的向下转换(从基类指针或引用转换为派生类指针或引用), // 它会在运行时检查类型转换的合法性。 // 如果转换成功,dynamic_cast 会返回一个指向目标类型的指针; // 如果转换失败(例如,尝试将一个基类指针转换为不相关的派生类指针),则返回一个空指针。 // 最后,将转换后的 T* 指针用于构造一个新的 rhref_ptr<T> 对象并返回 return dynamic_cast<T*>(rp.get()); } /// <summary> /// 用于对 rhref_ptr 类型的智能指针进行常量性转换 /// /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="Y"></typeparam> /// <param name="rp"></param> /// <returns></returns> template<class T, class Y> inline rhref_ptr<T> const_pointer_cast(const rhref_ptr<Y>& rp) { // 函数内部使用 const_cast<T*>(rp.get()) 进行常量性转换。 // rp.get() 会调用 rhref_ptr<Y> 类的 get 成员函数, // 返回其所管理的原始指针(类型为 Y*), // 然后使用 const_cast<T*> 将这个 Y* 类型的原始指针进行常量性转换, // 去除或添加指针的 const 或 volatile 限定符。 // 最后,将转换后的 T* 指针用于构造一个新的 rhref_ptr<T> 对象并返回 return const_cast<T*>(rp.get()); } }
最新发布
11-05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值