C++——运算符重载

一、定义:

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

运算符重载后优先级不变,结合律不变。

只能重载C++提供的运算符,不能自定义运算符。

C++中除了成员运算符“.”,取指针成员值运算符“.*”、作用域运算符“::”、“sizeof()”运算符、条件运算符“?:”不能重载,其他运算符均能重载。

语法:返回类型 operator 运算符 ();

运算符重载是为了满足自定义类型的运算,一般定义为类中的成员函数。例如:

class Person {
public:
	int m_A;
	int m_B;
};
void test01() {
	Person p1 = { 10,20 };
	Person p2 = { 15,30 };
	Person p3 = p1 + p2;
}

代码报错:没有与这些操作数匹配的运算符。就是因为目前 + 不能实现两个自定义类的相加。

二、+ 运算符重载

以上面代码为例:

  • 成员函数实现重载
class Person {
public:
	int m_A;
	int m_B;
	Person operator+(const Person &p) {
		Person temp;
		temp.m_A = this->m_A + p.m_A;
		temp.m_B = this->m_B + p.m_B;
		return temp;
	}
	Person operator+(int value) {
		Person temp;
		temp.m_A = this->m_A + value;
		temp.m_B = this->m_B + value;
		return temp;
	}
};
  • 全局函数实现重载
class Person {
public:
	int m_A;
	int m_B;
};
Person operator +(const Person &p1,const Person &p2) {
	Person temp;
	temp.m_A = p1.m_A + p2.m_A;
	temp.m_B = p1.m_B + p2.m_B;
	return temp;
}
Person operator +(const Person &p1, int value) {
	Person temp;
	temp.m_A = p1.m_A + value;
	temp.m_B = p1.m_B + value;
	return temp;
}

通过以上代码,可以实现p3=p1+p2,并且可以实现p3=p1+n; 

总结:当双目运算符重载时,可用成员函数也可用全局函数,且能发生函数重载。-、*、/号同理。

三、<< 左移运算符重载

C++ 中 <<左移运算符和cout联合,作为输出指令使用 cout<< 。输出指令的本质就是对<<运算符进行了重载,使cout<<具备了输出功能。cout 是一个ostream类的实例化对象,ostream叫做输出流,在C++中用来输出,cout就是最典型的输出流对象。

通过对<<左移运算符的重载,可实现自定义类型的输出。

#include
using namespace std;
#include
class Person {
public:
	string m_Name;
	int m_Age;
	//ostream &operator<<(ostream& cout) {
	//	cout << "姓名:" << m_Name << ",年龄:" << m_Age;
	//	return cout;
	//}
};
//ostream类未提供public的默认无参构造,无法创建新对象,所以将cout引用
//作为参数传入函数;为实现连续输出,需返回cout的引用。
ostream &operator<<(ostream& cout,const Person& p) {
	cout << "姓名:" << p.m_Name << ",年龄:" << p.m_Age ;
	return cout;
}
void test01() {
	Person p = { "zhangsan",19 };
	cout << p << endl;
}
int main(int argc, char const **argv) {
	test01();
	system("pause");
	return 0;
}

成员函数无法实现cout 和输出内容的前后位置关系,故以全局函数实现<<重载。当类中成员属性非public权限时,需将全局函数设置为类的友元函数。

友元函数:顾名思义就是这个全局函数是这个类的朋友,允许访问类中非public的成员属性。

#include
using namespace std;
#include
class Person {
	friend ostream& operator<<(ostream&, const Person&);
public:
	Person(string name, int age) :m_Name(name), m_Age(age) {};
private:
	string m_Name;
	int m_Age;
};

ostream &operator<<(ostream& cout,const Person& p) {
	cout << "姓名:" << p.m_Name << ",年龄:" << p.m_Age ;
	return cout;
}
void test01() {
	Person p = { "zhangsan",19 };
	cout << p << endl;
}
int main(int argc, char const **argv) {
	test01();
	system("pause");
	return 0;
}

四、++、--运算符重载 

自增自减运算符是单目运算符,且分为前置和后置,需要进行函数重载实现前置后置的区别。编译器提供了默认的后置运算符重载函数,以int虚参为区分实现函数重载。前置返回对象本身,具备连续运算功能,后置返回运算前的值,不具备连续运算功能,这也和原本的功能一致。上代码:

#include
using namespace std;
#include
class Person {
public:
	int m_A;
	int m_B;
	Person& operator++() {//前置++重载,返回计算后的对象
		this->m_A++;
		this->m_B++;
		return *this;
	}
	Person operator++(int) {   //后置++重载,返回计算前的值,编译器提供了后置++函数的重载,以int虚参区分
		Person temp=*this;
		m_A++;
		m_B++;
		return temp;
	}
};
ostream &operator<<(ostream& cout, const Person &p) {
	cout << p.m_A << " " << p.m_B ;
	return cout;
}
void test01() {
	
	Person p1 = { 10,20 };
	Person p2 = { 15,30 };
	cout << p1++ <<" "<< p1 << endl;
	cout << ++p2 <<" "<< p2 << endl;
}

int main(int argc, char const **argv) {
	test01();
	return 0;
}

五、 赋值运算符 = 的重载

当自定义类型中存在在堆区开辟的成员变量时,直接赋值就出现了浅拷贝情况,浅拷贝情况下,delete对象1,造成对象2中指针成员指向值改变。赋值运算符重载可以解决这个问题。但是,在未重构拷贝构造函数时,即使=已重载,Person p2=p1;该语句调用的依然是默认的拷贝构造函数,也就是浅拷贝。

#include
using namespace std;
#include
class Person {
public:
	Person() {
		m_Name = NULL;
	}
	Person(string name) {
		m_Name = new string(name);
	}
	Person(const Person& p) {		
		this->m_Name = new string(*p.m_Name);
	}
	Person& operator=(const Person& p) {
		if (m_Name) {
			delete m_Name;
		}
		m_Name = new string(*p.m_Name);
		return *this;
	}

	~Person() {
		if (m_Name) {
			delete m_Name;
		}
		m_Name = NULL;
	}

	string *m_Name;
};

void test01() {
	Person p1("zhangsan");
	Person p2 = p1 ;//未重构拷贝构造函数时,即使已进行了=重载,此语句依然是调用了默认的拷贝构造函数,也就是浅拷贝。
	cout << "p1的m_Name=" << p1.m_Name << endl;
	cout << "p2的m_Name=" << p2.m_Name << endl;
}

int main(int argc, char const **argv) {
	test01();
	return 0;
}

六、关系运算符重载

关系运算符重载需要确定比较条件,比如年龄。当p1.m_Age>p2.m_Age时,表示为p1>p2。

#include
using namespace std;
#include
class Person {
public:
	int m_Age;
	Person(int age):m_Age(age){}
	bool operator>(const Person& p) {
		return this->m_Age > p.m_Age;
	}
	bool operator<(const Person& p) {
		return this->m_Age < p.m_Age;
	}
	bool operator==(const Person& p) {
		return this->m_Age == p.m_Age;
	}
};

void test01() {
	Person p1(10);
	Person p2(15);
	cout << (p1 > p2) << endl;
	cout << (p1 == p2) << endl;
	cout << (p1 < p2) << endl;
}

int main(int argc, char const **argv) {
	test01();
	return 0;
}

七、函数调用符“()”的重载

目前我还没有发现特别的意义

#include
using namespace std;
#include
class Myprint {
public:
	void operator()(const string& str) {
		cout << str << endl;
	}
};
class Myadd {
public:
	int operator()(const int& a, const int& b) {
		return a + b;
	}
};
void test01() {
	Myprint print;
	print("Hello World!");
	Myadd add;
	cout << add(2, 3) << endl;
}

int main(int argc, char const **argv) {
	test01();
	return 0;
}

八、友元

友元包括:友元函数,友元类,友元成员函数。都是在类中用friend修饰,从而获得在该类中的特殊访问权限。

#include
using namespace std;
#include
class Person;
class Son {
public:
	int& getPassword(Person &p);
};
class Person {
	friend class Son;//友元类
	friend string& getName(Person& p);//友元全局函数
	friend int& Son::getPassword(Person& p);//友元成员函数
public:
	Person() {};
	Person(string name, int password) {
		m_Name = name;
		m_PassWord = password;
	}
private:
	string m_Name;
	int m_PassWord;
};
int& Son::getPassword(Person& p) {//需要先声明函数原型为友元,再实现函数体
	return p.m_PassWord;
}
string& getName(Person &p) {
	return p.m_Name;
}
void test01() {
	Person p("张三", 123456);
	Son s;
	cout << getName(p) << endl;
	cout << s.getPassword(p) << endl;
}
int main(int argc, char const **argv) {
	test01();
	return 0;
}

你可能感兴趣的:(c++,开发语言)