首页 > 代码库 > 【C/C++学院】(8)全局函数和类成员函数转化/友元/操作符重载

【C/C++学院】(8)全局函数和类成员函数转化/友元/操作符重载

1.全局函数和类成员函数转化

    全局函数和成员函数的相互转化:只需要修改一个指向本类的this指针;

#include <iostream>
using namespace std;

class Test
{
public:
	Test(int a, int b)
	{
		this->a = a;
		this->b = b;
	}
	//成员函数
	Test &Gadd2(Test &t2)
	{
		this->a = this->a + t2.a;
		this->b = this->b + t2.b;
		return *this;
	}
public:
	int a;
	int b;
};
//全局函数
Test &Gadd1(Test &t1, Test &t2)
{
	Test t3(0, 0);
	t3.a = t1.a + t2.a;
	t3.b = t1.b + t2.b;
	return t3;
}

//从成员函数转化为全局函数 只需要加一个 this指针(指向本类的类指针)
//从全局函数转化为类的成员函数是,需要减一个做左操作数参数
void main()
{
	Test t1(1, 2), t2(3, 4);
	//Test t3 = Gadd1(t1, t2);
	t1.Gadd2(t2);

	system("pause");
}

2.友元

2.1友元函数

#include "iostream"
using namespace std;
class Test2
{
public:
    //友元函数的特点是:有一个参数是友元类的指针或引用
    friend int OpMem(Test2 *p, int a); //友元函数
    Test2(int a, int b)
    {
        this->a = a;
        this->b = b;
    }
    int getA()
    {
        return this->a;
    }
protected:
private:
    int a;
    int b;
};
int OpMem(Test2 *p, int a)
{
    p->a = a;
    return 0;
}
void main()
{
    Test2 t1(1, 2);
    t1.getA();//没有friend的情况下,如果获取对象t1的私有数据,需要用get方法。
    OpMem(&t1, 10);
    system("pause");
}

2.2友元类

#include <iostream>
using namespace std;

class A
{
	friend class B;//B是A的友元类
public:
	void  Display() { cout << x << endl; };
private:
	int  x;
};
//设计模式中的组合场景。表象是设置b100, 本质上是修改a的数据。
class  B
{
public:
	void Set(int i) { Aobject.x = i; }
	void Display()  { Aobject.Display(); }
private:
	A  Aobject;
};

void main()
{
	B  Bobject;
	Bobject.Set(100);
	Bobject.Display();
	system("pause");
}


3.操作符重载

C++有许多内置的数据类型,包括int,char,double等,每一种类型都有许多运算符,例如加,减,乘,除等。当用户定义了类的对象时,两个对象之间是不能进行这些操作的,比如hyong类的对象a+b,这样的语句如果没有重载+运算符就会出错。但C++允许用户把这些运算符添加到自已的类中以方便类对象之间的运算就像内置类型的运算一样方便,比如对象a+b这样就很明白更容易懂,当然也可以在类中定义一个对象间相加的函数,比如a.add(b)调用函数add()以实现两个对象a和b相加,但是这条语句没有比a+b更容易让人理解。

3.1通过友元函数实现操作符重载,

#include <iostream>
using namespace std;
class Fushu
{
private:
    int a;
    int b;
    //通过友元函数实现+操作
    friend Fushu operator+(Fushu &c1, Fushu &c2);
public:
    Fushu(int a=0, int b=0)
    {
        this->a = a;
        this->b = b;
    }
    void print()
    {
        cout << a << "+" << b << "i" << endl;
    }
};
Fushu operator+(Fushu &c1, Fushu &c2)
{
    Fushu tmp;
    tmp.a = c1.a + c2.a;
    tmp.b = c1.b + c2.b;
    return tmp;
}
void main()
{
    Fushu c1(1, 2), c2(3, 4);
    Fushu c3 = c1+c2;
    c3.print();
    system("pause");
}

#include <iostream>
using namespace std;
class Fushu
{
private:
    int a;
    int b;
    //通过友元函数实现前++操作
    friend Fushu &operator++(Fushu &c2);
public:
    Fushu(int a=0, int b=0)
    {
        this->a = a;
        this->b = b;
    }
    void print()
    {
        cout << a << "+" << b << "i" << endl;
    }
};
Fushu &operator++(Fushu &c2)
{
    c2.a++;
    c2.b++;
    return c2;
}
void main()
{
    Fushu c1(1, 2), c2(3, 4);
    ++c2;
    
    c2.print();
    
    system("pause");
}

3.2通过类的成员函数实现操作符重载

#include <iostream>
using namespace std;
class Fushu
{
private:
    int a;
    int b;
    //通过友元函数实现+操作
    friend Fushu operator+(Fushu &c1, Fushu &c2);
public:
    //通过类的成员函数实现-操作
    Fushu operator-(Fushu &c2)
    {
        Fushu tmp;
        tmp.a = this->a - c2.a;
        tmp.b = b - c2.b;//此处的this可以省略
        return tmp;
    }
public:
    Fushu(int a=0, int b=0)
    {
        this->a = a;
        this->b = b;
    }
    void print()
    {
        cout << a << "+" << b << "i" << endl;
    }
};
Fushu operator+(Fushu &c1, Fushu &c2)
{
    Fushu tmp;
    tmp.a = c1.a + c2.a;
    tmp.b = c1.b + c2.b;
    return tmp;
}
void main()
{
    Fushu c1(1, 2), c2(3, 4);
    Fushu c3 = c1+c2;//operator+(c1,c2);
    c3.print();
//目标 通过类的成员函数,完成操作符重载
//1 要承认操作符重载是一个函数,要写函数原型
//2 写出函数调用语言 c1.operator-(c2)
//3 完善函数原型   
    Fushu c4 = c1 - c2;//operator-(c1,c2) -->c1.operator-(c2)-->Fushu operator-(Fushu &c2);
    c4.print();
    system("pause");
}

#include <iostream>
using namespace std;
class Fushu
{
private:
    int a;
    int b;
    //通过友元函数实现前++操作
    friend Fushu &operator++(Fushu &c2);
public:
    Fushu(int a=0, int b=0)
    {
        this->a = a;
        this->b = b;
    }
    void print()
    {
        cout << a << "+" << b << "i" << endl;
    }
public://通过类的成员函数实现前--操作
    Fushu& operator--()
    {
        this->a--;
        this->b--;
        return *this;
    }
};
Fushu &operator++(Fushu &c2)
{
    c2.a++;
    c2.b++;
    return c2;
}
void main()
{
    Fushu c1(1, 2), c2(3, 4);
    //通过友元函数实现前++操作
    ++c2;    
    c2.print();
    //通过类的成员函数实现前--操作
    --c2;    
    c2.print();
    system("pause");
}

综合:

#include <iostream>
using namespace std;

class Fushu
{
private:
	int a;
	int b;
	//通过友元函数实现前++操作
	friend Fushu &operator++(Fushu &c2);
	//通过友元函数实现后++操作
	friend Fushu operator++(Fushu &c2, int);//用缺省参数占位,跟前++区分
public:
	Fushu(int a=0, int b=0)
	{
		this->a = a;
		this->b = b;
	}
	void print()
	{
		cout << a << "+" << b << "i" << endl;
	}
public:
	//通过类的成员函数实现前--操作
	Fushu& operator--()
	{
		this->a--;
		this->b--;
		return *this;
	}
	//通过类的成员函数实现前--操作
	Fushu& operator--(int)//用缺省参数占位,跟后--区分
	{
		Fushu tmp;
		tmp = *this;
		this->a--;
		this->b--;
		return tmp;
	}
};

Fushu &operator++(Fushu &c2)
{
	c2.a++;
	c2.b++;
	return c2;
}

Fushu operator++(Fushu &c2, int)
{
	Fushu tmp;
	tmp = c2;
	c2.a++;
	c2.b++;
	return tmp;
}

void main()
{
	Fushu c1(1, 2), c2(3, 4);
	//通过友元函数实现前++操作
	++c2;	
	c2.print();
	//通过类的成员函数实现前--操作
	--c2;	
	c2.print();
	//通过友元函数实现后++操作
	c2++;
	c2.print();
	//通过类的成员函数实现后--操作
	c2--;
	c2.print();

	system("pause");
}


3.3操作符重载的正规写法

      通过友元函数可以获取友元类的私有属性,相当于获取了程序的一个后门。
#include <iostream>
using namespace std;

class Fushu
{
private:
	int a;
	int b;
	friend ostream& operator<<(ostream &cout, Fushu &c);
public:
	Fushu(int a=0, int b=0)
	{
		this->a = a;
		this->b = b;
	}
	void print()
	{
		cout << a << "+" << b << "i" << endl;
	}
public:
	//通过类的成员函数实现前++操作
	Fushu &operator++()
	{
		this->a++;
		this->b++;
		return *this;
	}
	//通过类的成员函数实现前--操作
	Fushu& operator--()
	{
		this->a--;
		this->b--;
		return *this;
	}
	//通过类的成员函数实现后--操作
	Fushu operator--(int)//用缺省参数占位,跟后--区分
	{
		Fushu tmp;
		tmp = *this;
		this->a--;
		this->b--;
		return tmp;
	}
	//通过类的成员函数实现后++操作
	Fushu operator++(int)//用缺省参数占位,跟后--区分
	{
		Fushu tmp;
		tmp = *this;
		this->a++;
		this->b++;
		return tmp;
	}
};

ostream& operator<<(ostream &co, Fushu &c)
{
	cout << "我是复数:" << endl;
	cout << c.a << "+" << c.b << "i" << endl;
	return co;
}

void main()
{
	Fushu c1(1, 2), c2(3, 4);
	++c2;	
	c2.print();

	--c2;	
	c2.print();

	c2++;
	c2.print();

	c2--;
	c2.print();

	cout << 1 << endl;
	cout << "hello" << endl;
	//函数返回值当左值的时候,需要返回一个对象的引用, 实现链式编程
	cout << c2 << "连续" << endl;
	//没有方法去在cout类里面添加函数operator<<,只能通过全局函数实现。
	//cout.operator<<( c1);
	//void operator<<(ostream &out, Complex &c1)

	system("pause");
}

3.4操作符重载在项目中的应用:

基本的数组框架
Array.h
//Array.h
#ifndef _ARRAY_H_
#define _ARRAY_H_

class Array
{
private:
	int mLength;//数组的长度
	int* mSpace;//内存空间

public:
	Array(int length);
	Array(const Array& obj);//copy构造函数
	int length();//取得数组长度
	void setData(int index, int value);
	int getData(int index);
	~Array();
};

#endif
Array.cpp
//Array.cpp
#include "Array.h"

Array::Array(int length)
{
	if (length < 0)
	{
		length = 0;
	}
	mLength = length;
	mSpace = new int[mLength];
}
Array::Array(const Array& obj)
{
	mLength = obj.mLength;
	mSpace = new int[mLength];
	for (int i = 0; i<mLength; i++)
	{
		mSpace[i] = obj.mSpace[i];
	}
}
int Array::length()
{
	return mLength;
}
void Array::setData(int index, int value)
{
	mSpace[index] = value;
}
int Array::getData(int index)
{
	return mSpace[index];
}
Array::~Array()
{
	mLength = -1;
	delete[] mSpace;
}
//ArrayTest.cpp
//ArrayTest.cpp
#include "Array.h"
#include <iostream>
using namespace std;

int main()
{
	Array a1(10);

	for (int i = 0; i<a1.length(); i++)
	{
		a1.setData(i, i);  //a[i] = 1;
	}

	for (int i = 0; i<a1.length(); i++)
	{
		printf("array %d: %d\n", i, a1.getData(i));
		// printf("array %d: %d\n", i, a1[i]));
	}

	Array a2 = a1;
	for (int i = 0; i<a2.length(); i++)
	{
		printf("array %d: %d\n", i, a2.getData(i));
	}
	system("pause");
	return 0;
}

重载[]  =  ==  !=操作符后的代码:
//Array.h
#ifndef _ARRAY_H_
#define _ARRAY_H_
#include <string.h>
class Array
{
private:
	int mLength;//数组的长度
	int* mSpace;//内存空间

public:
	Array(int length);
	Array(const Array& obj);//copy构造函数
	int length();//取得数组长度
	void setData(int index, int value);
	int getData(int index);
	~Array();
public:
	int & operator[](int i);
	void operator=(Array &a2);
	bool operator==(Array &a1);
	bool operator!=(Array &a1);
};

#endif

//Array.cpp
#include "Array.h"

Array::Array(int length)
{
	if (length < 0)
	{
		length = 0;
	}
	mLength = length;
	mSpace = new int[mLength];
}
Array::Array(const Array& obj)
{
	mLength = obj.mLength;
	mSpace = new int[mLength];
	for (int i = 0; i<mLength; i++)
	{
		mSpace[i] = obj.mSpace[i];
	}
}
int Array::length()
{
	return mLength;
}
void Array::setData(int index, int value)
{
	mSpace[index] = value;
}
int Array::getData(int index)
{
	return mSpace[index];
}
Array::~Array()
{
	mLength = -1;
	delete[] mSpace;
}

int& Array::operator[](int i)
{
	return this->mSpace[i];
}

void Array::operator = (Array &a2)
{
	if (this->mSpace != NULL)
	{
		delete[] mSpace;
	}	
	mLength = a2.mLength;
	mSpace = new int[mLength];
    memcpy(mSpace, a2.mSpace, mLength);
}

bool Array::operator==(Array &a1)
{
	//先比较长度
	if (mLength != a1.mLength)
	{
		return false;
	}
	//比较内容
	for (int i = 0; i < a1.mLength; i++)
	{
		if (a1[i] != mSpace[i])
		{
			return false;
		}
	}
	return true;
}
//利用相等判断不等 
bool Array::operator!=(Array &a1)
{
	return !(a1 == *this);
}

//ArrayTest.cpp
#include "Array.h"
#include <iostream>
using namespace std;

int main()
{
	Array a1(10);

	for (int i = 0; i<a1.length(); i++)
	{
		//a1.setData(i, i);  
		a1[i] = i;
	}
	
	for (int i = 0; i<a1.length(); i++)
	{
		//printf("array %d: %d\n", i, a1.getData(i));
		printf("array %d: %d\n", i, a1[i]);
	}

	Array a2 = a1;
	for (int i = 0; i<a2.length(); i++)
	{
		//printf("array %d: %d\n", i, a2.getData(i));
		printf("array %d: %d\n", i, a1[i]);
	}

	Array a3(10);
	a3 = a2; //执行=操作
	
	if (a2 == a1)
	{
		printf("相等");
	}
	else
	{
		printf("不相等");
	}
	system("pause");
	return 0;
}







【C/C++学院】(8)全局函数和类成员函数转化/友元/操作符重载