C++_友元函数和友元类、运算符重载

在C++中,我们使用类对数据进行了隐藏和封装,类的数据成员一般都定义为私有成员,成员函数一般都定义为公有的,以此提供类与外界的通讯接口。但是,有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁地访问类的数据成员,这时可以将这些函数定义为该函数的友元函数。除了友元函数外,还有友元类,两者统称为友元。友元的作用是提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。

友元函数 :
友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下:
friend 类型 函数名(形式参数);
友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。
一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
友元函数的调用与一般函数的调用方式和原理一致。
友元类 :
友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。
当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:
friend class 类名;
其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。

友元函数

例子如下:

#include <iostream>

using namespace std;

class A
{
public:
	//
	friend void modifyA(A *pA, int _a);
	A(int a, int b)
    {
		this->a = a;
		this->b = b;
	}
	int getA()
	{
		return a;
	}
private:
	int a, b;
};

void modifyA(A *pA,int _a)
{
	pA->a = _a;
}
int main()
{
	A a1(1, 2);
	cout << a1.getA() << endl;
	modifyA(&a1, 100);
	cout << a1.getA() << endl;
	system("pause");
	return 1;

}

说明:声明一个友元函数,来修改类的私有属性。
输出:
1
100
请按任意键继续. . .

友元类

#include

using namespace std;

class A
{
public:
//
friend void modifyA(A *pA, int _a);
friend class B;
A(int a, int b)
{
this->a = a;
this->b = b;
}
int getA()
{
return a;
}
private:
int a, b;
};

class B
{
public:

void set()
{
	objA.a = 10;
}

private:
A objA;
// int a, b;
};

void modifyA(A *pA,int _a)
{
pA->a = _a;
}
int main()
{
A a1(1, 2);
cout << a1.getA() << endl;
modifyA(&a1, 100);
cout << a1.getA() << endl;
system(“pause”);
return 1;

}
备注:在类a中声明, friend class B,然后再B中就可以访问类A的属性和方法了。

为什么设计友元类函数???(这个没完全听懂)

1.java—>1.class(字节码) == >class找到类的对象,直接修改类的私有属性。

运算符重载

所谓重载,就是重新赋予新的含义。函数重载就是对一个已有的函数赋予新的含义,使之实现新功能,因此,一个函数名就可以用来代表不同功能的函数,也就是”一名多用”。
运算符也可以重载。实际上,我们已经在不知不觉之中使用了运算符重载。例如,大 家都已习惯于用加法运算符”+”对整数、单精度数和双精度数进行加法运算,如5+8, 5.8 +3.67等,其实计算机对整数、单精度数和双精度数的加法操作过程是很不相同的, 但由于C++已经对运算符”+”进行了重载,所以就能适用于int, float, doUble类型的运算。
又如”<<“是C++的位运算中的位移运算符(左移),但在输出操作中又是与流对 象cout 配合使用的流插入运算符,”>>“也是位移运算符(右移),但在输入操作中又是与流对象 cin 配合使用的流提取运算符。这就是运算符重载(operator overloading)。C++系统对”<<“和”>>“进行了重载,用户在不同的场合下使用它们时,作用是不同 的。对”<<“和”>>“的重载处理是放在头文件stream中的。因此,如果要在程序中用”<< “和”>>”作流插入运算符和流提取运算符,必须在本文件模块中包含头文件stream(当然还应当包括”using namespace std“)。
现在要讨论的问题是:用户能否根据自己的需要对C++已提供的运算符进行重载,赋予它们新的含义,使之一名多用。?

代码如下:

#include <iostream>

using namespace std;

class Complex
{
public:
	int a, b;
public:
	Complex(int a = 0, int b = 0)
	{
		this->a = a;
		this->b = b;
	}
	void printCom(){
	   
		cout << a << "+" << b <<"i"<< endl;
	}
};
//第一步,定义全局函数。
Complex myAdd(Complex &c1, Complex &c2)
{
	Complex tmp(1, 2);
	return tmp;
}
//第二步,对函数名进行改造。
Complex operator+(Complex &c1, Complex &c2)
{
	Complex tmp(c1.a+c2.a, c1.b+c2.b);
	return tmp;
}
int main()
{
	int a = 0, b = 0;
	int c;
	c = a + b;
	Complex c1(1, 2) , c2(2, 3);
	Complex c3;  //用户自定义数据类型,C++默认情况下是不知道如何运算的。
	// c3 = c1 + c2;

	//C++编译器应该给我们程序员提供一种机制。。。
	//让自定义数据类型有机会进行运算符操作,运算符重载体制。


	/*Complex c4 = myAdd(c1, c2);
	Complex c4 = operator+(c1, c2);*/
    //第三步, 直接调用。
	Complex c4 = c1 + c2;
	c4.printCom();
	system("pause");
	return 1;
}

运算符重载的本质是 函数调用。
输出结果 3+5i;

重载等号运算符

#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>
using namespace std;

//

class  Name
{
public:
	Name(const char *myp)
	{
		m_len = strlen(myp);
		m_p =(char *) malloc(m_len + 1); //
		strcpy(m_p, myp);
	}

	//Name obj2 = obj1;
	//解决方案: 手工的编写拷贝构造函数 使用深copy
	Name(const Name& obj1)
	{
		m_len = obj1.m_len;
		m_p = (char *)malloc(m_len + 1);
		strcpy(m_p, obj1.m_p);
	}

	//obj3 = obj1;  // C++编译器提供的 等号操作 也属 浅拷贝
	//obj3.operator=(obj1)

	Name& operator=(Name &obj1)
	{
		//先释放旧的内存
		if (this->m_p != NULL)
		{
			delete[] m_p;
			m_len = 0;
		}
		//2 根据obj1分配内存大小
		this->m_len = obj1.m_len;
		this->m_p = new char [m_len+1];
		
		//把obj1赋值
		strcpy(m_p, obj1.m_p);
		return *this;
	}
	
	~Name()
	{
		if (m_p != NULL)
		{
			free(m_p);
			m_p = NULL;
			m_len = 0;
		}
	}
protected:
private:
	char *m_p ;
	int m_len; 
};

//对象析构的时候 出现coredump
void objplaymain()
{
	Name obj1("abcdefg");
	Name obj2 = obj1;  //C++编译器提供的 默认的copy构造函数  浅拷贝
	Name obj3("obj3");
	obj3 = obj1;  // C++编译器提供的 等号操作 也属 浅拷贝
	//obj3.operator=(obj1)
	//operato=(Name &obj1)
	obj1 = obj2 = obj3;
	//obj2.operator=(obj3);
	//obj1 = void;
}
void main()
{
	objplaymain();
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

内存示意图
视频看到了,第十个。

成员函数和友元函数完成二元运算符重载

全局函数、类成员函数方法实现运算符重载步骤:
1)要承认操作符重载是一个函数,写出函数名称operator+ ()
2)根据操作数,写出函数参数
3)根据业务,完善函数返回值(看函数是返回引用 还是指针 元素),及实现函数业务

成员函数实现减号-运算符重载

#include <iostream>

using namespace std;
class Complex
{
public:
	int a, b;
public:
	Complex(int a = 0, int b = 0)
	{
		this->a = a;
		this->b = b;
	}
	void printCom(){
		cout << a << "+" << b <<"i"<< endl;
	}
	Complex operator-(Complex &c2)      
	{
		Complex tmp(c2.a, c2.a);
		return tmp;
	}

};
//第一步,定义全局函数。
Complex myAdd(Complex &c1, Complex &c2)
{
	Complex tmp(1, 2);
	return tmp;
}
//第二步,对函数名进行改造。
Complex operator+(Complex &c1, Complex &c2)
{
	Complex tmp(c1.a+c2.a, c1.b+c2.b);
	return tmp;
}
int main()
{
	//int a = 0, b = 0;
	//int c;
	//c = a + b;
	Complex c1(1, 2) , c2(2, 3);
	Complex c3;  //用户自定义数据类型,C++默认情况下是不知道如何运算的。
	//
	c3= c1.operator-(c2);
	c3.printCom();
	//c4.printCom();
	system("pause");
	return 1;
}

输出 2+2i

一元运算符重载(全局函数方法实现++ (–成员函数实现))

#include <iostream>

using namespace std;
class Complex
{
public:
	int a, b;
	friend Complex operator+(Complex &c1, Complex &c2);
public:
	Complex(int a = 0, int b = 0)
	{
		this->a = a;
		this->b = b;
	}
	void printCom(){
		cout << a << "+" << b <<"i"<< endl;
	}
	Complex operator-(Complex &c2)
	{
		Complex tmp(this->a-c2.a,this->b- c2.b);
		return tmp;
	}
	Complex &operator--()
	{
		this->a--;
		this->b--;
		return *this;

	}

};
//第一步,定义全局函数。
Complex myAdd(Complex &c1, Complex &c2)
{
	Complex tmp(1, 2);
	return tmp;
}
//第二步,对函数名进行改造。
Complex operator+(Complex &c1, Complex &c2)
{
	Complex tmp(c1.a+c2.a, c1.b+c2.b);
	return tmp;
}
Complex& operator++(Complex &c1)
{
	c1.a++;
	c1.b++;
	return c1;
}
int main()
{
	//int a = 0, b = 0;
	//int c;
	//c = a + b;
	Complex c1(11, 21) , c2(2, 3);
	//Complex c3;  //用户自定义数据类型,C++默认情况下是不知道如何运算的。
	
	//c3= c1.operator-(c2);
	//c3.printCom();
	//++c1;
	//c1.printCom();
	//c4.printCom();
	//成员函数方法实现--运算符。
	c1.operator--();
	c1.printCom();
	system("pause");
	return 1;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值