运算符重载——c++

25 篇文章 0 订阅

运算符重载



定义:运算符重载:就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。

定义重载的运算符就像定义函数,只是该函数的名字是operator@,这个@符号就代表着被重载的运算符。其中函数的参数取决于两个因素:运算符是一个参数的还是两个参数

如果是全局函数那么一元就是一个参数,两元就是两个参数。

如果是成员函数,一元的成员函数不需要参数,两元的成员函数需要一个参数。

(例如下面的+法运算符)



加号运算符的重载(+)


例如:有个person类,类中有两个成员变量:a,b。然后创建的对象Person1中,a,b的值分别是1,1;创建的对象Person2中,a,b的值分别是2,2。那么想重新定义一种加法:创建新的对象Person3使得a,b的值等于另外两个对象的变量的和。即Person3 = Person1+Person2.即(3,3)。

成员函数重载
class Person
{
public:
	Person(int a,int b):m_a(a),m_b(b){}
	int m_a;
	int m_b;

public:
	Person personAddPerson(Person& p)
	{
		Person temp(0, 0);
		temp.m_a = this->m_a + p.m_a;
		temp.m_b = this->m_b + p.m_b;
		return temp;
	}
	Person operator+(Person& p)//系统给的名字
	{
		Person temp(0, 0);
		temp.m_a = this->m_a + p.m_a;
		temp.m_b = this->m_b + p.m_b;
		return temp;
	}
};

int main()
{
	Person p1(10, 10);
	Person p2(10, 10);
	Person p3 = p1.personAddPerson(p2);
	cout << p3.m_a << endl;//20
	Person p4 = p1 + p2;
	cout << p4.m_a << endl;//20

	return 0;
}

personAddPerson这个函数很好理解,就是创建了一个成员函数,然后分别让对象p1和p2的两个成员变量相加。然后调用的时候如同p3的调用结果。 而operator+这个成员函数是编译器帮忙规定的,也可以使用**本质:Person p3 = p1.operator+(p2)**来调用,但是编译器就可以帮忙简化为: Person p3 = p1+p2;


全局函数重载

(这个时候需要两个参数)

Person operator+(Person& p1, Person& p2)
{
	Person temp(0,0);
	temp.m_a = p1.m_a + p2.m_a;
	temp.m_b = p1.m_b + p2.m_b;
	return temp;
}

在写完了这个全局函数以后,如果想要调用这个函数。原先:本质:Person p3 = operator+(p1,p2);现在简化为:Person p3 = p1+p2;

这就是运算符重载

运算符的重载也是可以发生函数的重载的。

比如:将上面的operator+的全局函数的参数改成一个是Person类型,一个是int类型,那么也是可以调用成功的,至于怎么用就看自己的操作代码。



左移运算符重载(<<)


创建的对象是不能直接输出的。

class Person
{
public:
	Person(int a, int b)
	{
		this->m_A = a;
		this->m_B = b;
	}
	int m_A;
	int m_B;
};

int main()
{
	Person p1(10, 20);
	//cout << p1 ;
	return 0;
}

如果直接想将p1这个对象打印,这种代码运行是肯定会报错的。

试图利用成员函数做“<<”符号的重载。

//原先加法的是“+”: a+b 也就相当于 a.operator+(b)
//现在是“<<”:p.operator<<(cout) 相当于 p<<cout 这样写与平常的cout<<p是相反的,所以要实现<<符号的重载还是使用全局函数比较好。

全局函数重载

那么就需要两个参数了,一个就是cout,一个就是对象p1。

cout的数据类型是输出流对象,是用输出流类创建出来的对象。

class Person
{
public:
	Person(int a, int b)
	{
		this->m_A = a;
		this->m_B = b;
	}
	int m_A;
	int m_B;
};

void operator<<(ostream& cout,Person& p1)
{
	cout << "m_A = " << p1.m_A <<"  m_B=" << p1.m_B << endl;
}

int main()
{
	Person p1(10, 20);
	cout << p1;
	return 0;
}
//输出的结果是:m_A = 10  m_B=20

使用全局函数就可以控制参数的前后位置。比如上代码中,必须保证cout在<<的前面,p1在<<的后面,那么在设置全局函数的时候也要保证cout参数在前面,p1参数在后面。

但是这样发现那就没有办法:cout<<p1<<endl;

如果想写这样的链式编程的话,就会报错,必须保证cout<<p1的返回结果是ostream类型的cout对象。(把本体返回)

如果将cout对象返回了以后,一切就回归正常,那么程序也正常的执行换行,与cout<<endl;一样。

ostream operator<<(ostream& cout,Person& p1)
{
	cout << "m_A = " << p1.m_A <<"  m_B=" << p1.m_B << endl;
}

如果将成员变量权限改成私有,那么就使用友元(将全局函数作为友元,friend后面直接加函数就可)

class Person
{
	friend ostream& operator<<(ostream& cout, Person& p1);
public:
	Person(int a, int b)
	{
		this->m_A = a;
		this->m_B = b;
	}
private:
	int m_A;
	int m_B;
};
	
ostream& operator<<(ostream& cout,Person& p1)//注意参数和返回值都是引用
{
	cout << "m_A = " << p1.m_A << "  m_B=" << p1.m_B << endl;
	return cout;
}

int main()
{
	Person p1(10, 20);
	cout << p1 << endl;
	cout << endl;
	return 0;
}


递增运算符重载(++)


前置++和后置++的符号都是++,那么怎么做区分呢?

前置:void operator(){}

后置:void operator(int){}

后置的函数时有int(占位参数)的。

重载代码的一步步实现:

class MyInter//自己创建的int类
{
public:
	MyInter()
	{
		m_num = 0;
	} 
private:
	int m_num;
};

void test01()
{
	MyInter myInt;
	//cout << myInt << endl;
}

首先创建一个自己的类。然后发现cout<<myInt<<endl是会报错的,因为编译器不认识MyInter类,所以需要对<<进行重载(与上相同)

既然要打印MyInter类中的私有成员变量,那么就需要将这个重载函数设置为友元。

class MyInter//自己创建的int类
{
	friend ostream& operator<<(ostream& cout, MyInter& myInt);//设置友元,使函数可以访问私有权限的成员变量
public:
	MyInter()
	{
		m_num = 0;
	}
private:
	int m_num;
};

ostream& operator<<(ostream& cout,MyInter& myInt)
{
	cout << myInt.m_num << endl;
	return cout;
}

void test01() 
{
	MyInter myInt;
	cout << myInt << endl;
}

int main()
{
	test01();
	return 0;
}

前置++

这个时候在test01中如果要求实现myInt的前置++操作,那么直接++myInt编译器是不认识的,所以需要对前置++进行重载。使用成员函数的方法进行重载。

class MyInter//自己创建的int类
{
	friend ostream& operator<<(ostream& cout, MyInter& myInt);//设置友元,使函数可以访问私有权限的成员变量
public:
	MyInter()
	{
		m_num = 0;
	}
	void operator++()
	{
		this->m_num++;
	}
private:
	int m_num;
};

这是时候在输出++myInt,输出的结果就是1.

但是cout << ++myInt << endl这个时候就报错的了,因为系统不认识。所以经过++运算后的结果(返回值)应该是它本身,毕竟下一次++也是在自己身上进行++的。所以返回自己就是return *this;然后函数的返回值也应该改成自身的类型:MyInter &。

class MyInter//自己创建的int类
{
	friend ostream& operator<<(ostream& cout, MyInter& myInt);//设置友元,使函数可以访问私有权限的成员变量
public:
	MyInter()
	{
		m_num = 0;
	}

	MyInter& operator++()
	{
		this->m_num++;
		return *this;
	}

private:
	int m_num;
};

这样进行的

cout<<++(++myInt)<<endl;
cout<<myInt<<endl;

两个结果都是2./但是,如果将上面的重载函数的返回值改成数值而不是引用了呢?MyInter& —>MyInter:

输出的结果分别是2,1 .很容易想啊,如果改成数值了以后,在第一次自增完了以后传过去的不再是myInt,而是值1,所以输出的值虽然是2,但是myInt的值是1.

后置++

需要先记录初始状态,

class MyInter//自己创建的int类
{
	friend ostream& operator<<(ostream& cout, MyInter& myInt);//设置友元,使函数可以访问私有权限的成员变量
public:
	MyInter()
	{
		m_num = 0;
	}

	//前置++重载
	MyInter& operator++()
	{
		this->m_num++;
		return *this;
	}
	//后置++重载
	MyInter operator++(int)
	{
		MyInter temp = *this;//先记录初始状态
		this->m_num++;
		return temp;
	}
	//不能返回以引用(MyInter&)的形式返回,因为这个引用temp是临时的,只在函数中创建的,出了函数就释放了。
	//所以后置++的返回值和前置++的返回值是不一样的,后置++返回的是一个值。
private:
	int m_num;
};

所以后置++返回的是值,所以后置++不能进行链式的运算。(myInt++)++这样的写法是错误的。第一次后置++的返回值已经是值了,不是引用了。

总结代码:(有点小错待解决)

class MyInter//自己创建的int类
{
	friend ostream& operator<<(ostream& cout, MyInter& myInt);//设置友元,使函数可以访问私有权限的成员变量
public:
	MyInter()
	{
		m_num = 0;
	}

	//前置++重载
	MyInter& operator++()
	{
		this->m_num++;
		return *this;
	}
	//后置++重载
	MyInter operator++(int)
	{
		MyInter temp = *this;//先记录初始状态
		this->m_num++;
		return temp;
	}
	//不能返回以引用(MyInter&)的形式返回,因为这个引用temp是临时的,只在函数中创建的,出了函数就释放了。
	//所以后置++的返回值和前置++的返回值是不一样的,后置++返回的是一个值。


private:
	int m_num;
};

ostream& operator<<(ostream& cout,MyInter& myInt)
{
	cout << myInt.m_num < endl;
	return cout;
}


void test01() 
{
	MyInter myInt;
	++myInt;
	cout << ++myInt << endl;
}
void test02()
{
	MyInter myInt;
	myInt++;
	//cout << myInt++;
	//这里会报错,显示需要MyInter类型的数据,但是我提供的是个值。但后置++返回的本来就是值啊。
}

int main()
{
	test02();
	return 0;
}

补充:前置的效率要高于后置,因为前置没有创建新的对象,后置用值的方式返回,需要创建新的对象(拷贝构造)。 将现在对象的所有的信息全部复制一遍,然后传给新的对象,然后最后再返回这个对象的值。其实本质上的效率差不了太多,如果数据量大的话,可以优先使用前置++。



指针运算符重载


class Person
{
public:
   Person(int age)
   {
   	cout << "Person的有参构造调用" << endl;
   	this->m_age = age;
   }
   void showAge()
   {
   	cout << "年龄为: " << this->m_age << endl;
   }
   ~Person()
   {
   	cout << "Person的析构调用" << endl;
   }

   int m_age;
};

int main()
{
   //Person p(100);//将对象开辟到栈上了,这个时候对象是由编译器free的。
   Person* p = new Person(18);//将对象开辟到堆上(返回的是一个指针),这个时候是由自己free的。
   p->showAge();//与 (*p).showAge() 是相同的。
   delete(p);//只有加上这一句才会调用析构

   return 0;
}

见上面的经典代码,发现如果在堆上创建对象的话是需要自己将创建的对象释放掉的,所以为了防止自己忘了将对象释放掉,那么可以设计一种智能指针,管理new出来的对象的释放。(这种只能指针也是一种类)

class Person
{
public:
	Person(int age)
	{
		cout << "Person的有参构造调用" << endl;
		this->m_age = age;
	}
	void showAge()
	{
		cout << "年龄为: " << this->m_age << endl;
	}
	~Person()
	{
		cout << "Person的析构调用" << endl;
	}

	int m_age;
};

class SmartPoint
{
public:
	SmartPoint(Person* person)
	{
		this->m_person = person;
	}
	~SmartPoint()
	{
		if (this->m_person!=NULL)
		{
			delete this->m_person;
			this->m_person = NULL;
		}
	}
private:
	Person* m_person;
};

int main()
{
	SmartPoint sp(new Person(18));//这里的sp对象是创建在栈上的,所以是可以自动的执行自己的析构代码,
	//在析构代码中进行对象中成员m_person的判断,并将这个成员给释放掉。所以有了这个智能指针类以后,不需要自己将person对象释放了,
	//只要将智能指针对象创建出来,就可以自动得调用它的析构(将person对象释放)。

	return 0;
}

但是如果想进行操作sp->showAge();这种写法是不可以的,因为sp的有关类中没有showAge函数,showAge()函数是它的成员函数的相关类中的,而且如果想调用->需要保证调用对象是个指针,而这个sp是一个spartpoint类型的的对象。如果想强制性的使得操作写法成立,那么就需要重新定义->.(需要在类中做重载)

正常来说,应该是指针才能调用->,所以重载的函数的返回值就应该是个指针, 而且还应该是Person* 的指针,这样直接将自己维护的指针返回就可以了,m_person的类型就是Person*。

在智能指针类中添加构造:

class SmartPoint
{
public:
	SmartPoint(Person* person)
	{
		this->m_person = person;
	}
	~SmartPoint()
	{
		if (this->m_person!=NULL)
		{
			delete this->m_person;
			this->m_person = NULL;
		}
	}
	Person* operator->()
	{
		return m_person;
	}
private:
	Person* m_person;
};

这样就可以直接调用:

int main()
{
	SmartPoint sp(new Person(18));
	sp->showAge();
	return 0;
}

如果想让这个对象看作是一个指针,还应该可以进行解引用:

(*sp).showAge()也应该是可以的,所以还应该对 *进行重载。

class SmartPoint
{
public:
   SmartPoint(Person* person)
   {
   	this->m_person = person;
   }
   ~SmartPoint()
   {
   	if (this->m_person!=NULL)
   	{
   		delete this->m_person;
   		this->m_person = NULL;
   	}
   }
   Person* operator->()//重载->运算符
   {
   	return m_person;
   }
   Person& operator*()//重载*运算符,返回指针的自身
   {
   	return *(m_person);//对这个指针进行解引用返回
   }
private:
   Person* m_person;
};

所有代码:

class Person
{
public:
	Person(int age)
	{
		cout << "Person的有参构造调用" << endl;
		this->m_age = age;
	}
	void showAge()
	{
		cout << "年龄为: " << this->m_age << endl;
	}
	~Person()
	{
		cout << "Person的析构调用" << endl;
	}

	int m_age;
};

class SmartPoint
{
public:
	SmartPoint(Person* person)
	{
		this->m_person = person;
	}
	~SmartPoint()
	{
		if (this->m_person!=NULL)
		{
			delete this->m_person;
			this->m_person = NULL;
		}
	}
	Person* operator->()//重载->运算符
	{
		return m_person;
	}
	Person& operator*()//重载*运算符,返回指针的自身
	{
		return *(m_person);//对这个指针进行解引用返回
	}
private:
	Person* m_person;
};

int main()
{
	SmartPoint sp(new Person(18));
	sp->showAge();
	(*sp).showAge();
	return 0;
}

总结:就是原先有个person类,然后在类中写了个展示年龄的函数,然后创建了个有参构造。然后创建了个智能指针的类,成员函数是一个person*的变量。因为创建智能指针对象的时候是在栈上创建的,所以可以直接将对象delete掉,同时在析构函数中还可以加一句,顺便将创建的person类的对象也同时释放掉,这就解决了容易忘记的情况。这个时候又想能不能使用智能指针的对象来调用person中的函数?智能指针对象中有个指针就是person的指针,但是又不能直接sp->showAge(),因为这个对象sp不是person *类型的,所以可以重载->,使得只要是smartpoint的对象使用->,就可以返回自己所一直维护的指针m_person.

第一个功能体现出的是它的智能功能,第二个功能体现出的是它的指针功能。这个类不但可以帮助任务free对象,而且还可以当作指针使用。

注意一点:将对象转换成指针的时候:sp->showAge()实际上应该是sp->->showAge(),sp->返回的是person*的m_age,还应该进行一步的 ->,但是这里编译器进行优化了,两个->这样反而是错误的。

(实际用途不多)



赋值运算符重载(=)


class Person
{
public :
	int m_Age;
};


int main()
{
	Person p1;
	p1.m_Age = 10;
	//Person p2(p1);//这样的写法是拷贝构造函数。
	//Person p2 = p1;//这样的写法也是拷贝构造函数。
	Person p2;
	p2 = p1;//如果这样写,那么就不会拷贝构造函数了,而是会进行赋值操作
	cout << p2.m_Age << endl;//结果是10

	return 0;
}

从上面的函数看出来:对象和对象能够直接赋值?赋值运算符为什么能区分对象呢?

因为:之前说过编译器默认给一个类至少添加3个函数:默认构造,析构 ,拷贝构造(值拷贝),但其实是4个,还有一个是**operator=**值拷贝),这个本身也是一个函数。

class Person
{
public :
	Person(const char* name, int age)
	{
		this->m_Name = new char[strlen(name) + 1];//在堆上开辟了空间,需要释放。
		strcpy(this->m_Name, name);
		this->m_Age = age;
	}
	int m_Age;
	char* m_Name;

	~Person()//在Person的析构中将m_name的空间释放。(在释放Person类的对象的时候顺便将m_name也释放)
	{
		if (this->m_Name != NULL)
		{
			delete [] this->m_Name;
			this-> m_Name = NULL;
		}
	}
};


int main()
{
	Person p1("tom", 10);
	Person p2("jerry", 20);

	p2 = p1;//如果这样写,那么就不会拷贝构造函数了,而是会进行赋值操作
	cout << p2.m_Age << endl;//结果是10

	return 0;
}

ps补充:先打断一下,写代码的时候发现不能直接将“tom“当作单数传到char* name,必须在前面加const。以后写有参构造的时候要注意一下。

首先,这样写肯定是会报错的。因为p2的信息已经和p1的是一样了,浅拷贝问题(当程序结束自动调用析构函数的时候会删除两个相同的字符串指针)堆区的内容重复的释放。

这个时候可以选择重载一下=操作符。在之前有个类似的情况,其他代码一样,在创建p2的时候是Person p2(p1),当时的问题也是浅拷贝问题,原因是调用的是编译器的拷贝构造函数所以造成了浅拷贝问题,解决方法就是自己重新写个拷贝构造函数Person(const Person&p),进行深拷贝(直接拷贝对象)。我们现在这里用的是赋值操作,但是也是会出现浅拷贝问题。

接下来重载一下+运算符就ok:

在p2 = p1中,p1就是传进去的参数。

class Person
{
public :
	Person(const char* name, int age)
	{
		this->m_Name = new char[strlen(name) + 1];//在堆上开辟了空间,需要释放。
		strcpy(this->m_Name, name);
		this->m_Age = age;
	}
	int m_Age;
	char* m_Name;

	~Person()//在Person的析构中将m_name的空间释放。(在释放Person类的对象的时候顺便将m_name也释放)
	{
		if (this->m_Name != NULL)
		{
			delete [] this->m_Name;
			this-> m_Name = NULL;
		}
	}
	void operator=(const Person& p)//对=重载,加const是为了防止不小心将传进来的对象修改
	{
		//先判断原来的堆区是否有内容,如果有内容先释放。后来测试的时候发现不释放也是可以的。
		if (this->m_Name != NULL)
		{
			delete[]this->m_Name;
			this->m_Name = NULL;
		}
		//进行深拷贝工作:
		this->m_Name = new char[strlen(p.m_Name) + 1];//在堆上创建空间
		strcpy(this->m_Name , p.m_Name);
		this->m_Age = p.m_Age;
	}
};


int main()
{
	Person p1("tom", 10);
	Person p2("jerry", 20);

	p2 = p1;//如果这样写,那么就不会拷贝构造函数了,而是会进行赋值操作
	cout << p2.m_Age << endl;//结果是10

	return 0;
}

如果进行:

int a = 10;
	int b = 20;
	int c = b = a;
	cout << a << b << c<< endl;
//最后的结果都是10

因为将a 的值赋给了b,又将b 的值赋给了c;所以最后的结果都是10.

但是如果三个数据都是对象的话运行就会报错。(p3 = p2 =p1)

因为先执行p2 = p1,返回的结果是void类型的(见上面自己的重载的代码),将一个void数据赋给p3肯定是会出错的。

改进:p2 在调用完 = 号以后的返回值应该还是p2才可以(这样等会p3执行=的时候返回值才可以是p3 的数据类型),所以应该返回本体类型而不是void。

Person& operator=(const Person& p)//对=重载,加const是为了防止不小心将传进来的对象修改
	{
		//先判断原来的堆区是否有内容,如果有内容先释放。
		if (this->m_Name != NULL)
		{
			delete[]this->m_Name;
			this->m_Name = NULL;
		}
		//进行深拷贝工作:
		this->m_Name = new char[strlen(p.m_Name) + 1];//在堆上创建空间
		strcpy(this->m_Name , p.m_Name);
		this->m_Age = p.m_Age;
		return *this;
	}

这是为了严谨才这么做的。

这里的=运算符重载是因为有属性指向堆区了,在释放的时候导致堆区的内容进行重释放了,所以才要对=运算符进行重载。但是如果创建的属性都是栈上的,那么也不需要堆=运算符进行重载。

这个时候如果写:Person p4 = p3,那么在写的时候编译器还是会崩的,因为这里的不是赋值运算,而是调用的系统的拷贝构造运算,而刚才仅仅是将=运算符进行重载,没有处理拷贝构造函数,导致如果调用拷贝构造函数函数会出现浅拷贝的问题。

//这里就不需要像上面那样对堆里之前有没有东西进行判断了,因为拷贝构造都是从无到有的,不需要判断,直接深拷贝。
Person(const Person&p)
{
    this->m_Name = new char[strlen(p.m_Name) + 1];//在堆上创建空间
		strcpy(this->m_Name , p.m_Name);
		this->m_Age = p.m_Age;
}



关系运算符的重载(==)

class Person
{
public:
	Person(string name ,int age)
	{
		this->m_Age = age;
		this->m_Name = name;
	}

	string m_Name;
	int m_Age;
};

int main()
{
	Person p1("TOM", 18);
	Person p2("TOM", 18);
	if (p1 == p2)
	{
		cout << "一样大" << endl;
	}
	return 0;
}

这样写是肯定会报错的,因为两个对象之间不能这样直接比较。

所以要对==进行重载,由于 ==是双目运算符,所以需要传进来一个参数p2

class Person
{
public:
	Person(string name ,int age)
	{
		this->m_Age = age;
		this->m_Name = name;
	}
	bool operator==(Person& p)
	{
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
		{
			return true;
		}
		else
			return false;
	}

	string m_Name;
	int m_Age;
};

int main()
{
	Person p1("TOM", 18);
	Person p2("TOM", 18);
	if (p1 == p2)
	{
		cout << "一样大" << endl;
	}
	return 0;
}

这样输出的结果就是:”一样大“

!=运算符也是同样的道理:

class Person
{
public:
	Person(string name ,int age)
	{
		this->m_Age = age;
		this->m_Name = name;
	}
	bool operator==(Person& p)
	{
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
		{
			return true;
		}
		else
			return false;
	}

	bool operator!=(Person& p)
	{
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
		{
			return false;
		}
		else
			return true;
	}

	string m_Name;
	int m_Age;
};

int main()
{
	Person p1("TOM", 18);
	Person p2("TOM", 17);
	if (p1 != p2)
	{
		cout << "不一样大" << endl;
	}
	return 0;
}

这样输出的结果就是”不一样大“


这个关系运算符的实用性比较强




函数调用运算符的重载(小括号)

就是重载小括号

class MyPrint
{
public :
   void operator()(string text)
   {
   	cout << text << endl;
   }
};

class MyAdd
{
public:
   int operator()(int a, int b)
   {
   	return a + b;
   }
};



void test01()
{
   MyPrint myprint;
   myprint("hello world");//仿函数
   //这里的myprint不是一个函数名,而是一个对象。通常叫这个对象为 函数对象。
   
   //这种仿函数是十分灵活的:
   MyAdd myadd;
   cout << myadd(3, 4) << endl;

   //仿函数可以结合匿名对象使用
   //匿名对象:类+(),这个对象在执行完这一句之后就释放了,很适合与仿函数结合。
   //这样就不用再自己创建对象了,起名字还费劲
   cout << MyAdd()(1, 1) << endl;
}

int main()
{
   test01();
   return 0;
}

所以,仿函数就是对()进行重载。




不要重载 &&,||

具有短路特性:首先会计算左边的值,如果左边的值完全能够决定结果,那么就不需要计算右边的值了。

这种短路特性是没法模拟的。




总结

1,<<>>只能通过全局函数配合友元进行重载(因为cout在左边,正常的参数都应该在右边)

2,= , [ ] , ( )-> 运算符都只能通过成员函数进行重载。

3,不要重载&&和||操作符,因为无法实现短路规则。




中括号[ ]的重载略。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是小明同学啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值