如何在 C++ 中使用 Friend 修饰符和示例
如果您信任他/她,您会将某人视为您的朋友,然后您会授予您的朋友更高级别的特权。
有人可能会说,你朋友的朋友也是你的朋友。但是,正如我们将看到的,在 C++ 中情况并非如此。
在 C++ 中,您应该准确说明您信任的人。这样,你对你的朋友会有更多的控制,他们也可以对你作为朋友有更多的限制。
如何定义好友修饰符
以下是您可以使用友元修饰符的几种情况:
- 它可以用于独立函数、不同类的方法、完整类、模板函数甚至模板类。
- 您还可以使用带有朋友修饰符的非成员函数。在这种情况下,该函数将没有“this”作为指针,并且该函数可以访问您的类中的所有数据。
- 如果您只想限制一个方法(或少数几个选择性方法)使用来自其他类的数据,则不需要将该类称为友元类,这在更极端的情况下可以称为友元类。
- 此外,模板函数和类与通常的函数和类类似,但它们并不关心它们处理的数据类型,它们也可以有朋友。
在某种程度上,您可以说朋友压倒了诸如私有、公共或受保护之类的修饰符。换句话说,朋友修饰符使从已经提到的访问限制中获得的限制无效。
那么,我们如何实现朋友修饰符呢?
class CSomeClass
{
...
friend someType FriendFunction( SomeArguments);
...
};
在上面的代码片段中,您使用“friend”修饰符来通知编译器您将信任 FriendFunction。在这种情况下,您应该通知您的编译器您正在使用的函数名称、返回数据类型和参数。
之后,您将独立函数作为类实现的一部分来实现,但不使用友元修饰符:
someType FriendFunction(SomeArguments);
如果您只想将一种方法作为您的类的朋友,您可以如下所述调用它。
class CSomeClass {
...
friend Return_Type CSomeOtherClass::SomeMethod(Different_Data_Types as arguments);
...
};
在极端情况下,您可以将整个类称为友元类,这样友元类将可以访问其他实体通常不可见的数据,因此可能无法获得隐藏的数据。
要实现这一点,您可以使用以下代码片段:
class CSomeClass;
...
class CFriendClass
{
...
void SomeMethod( CSomeClass object);
...
};
接下来,您创建一个将 CFriendClass 作为朋友的类。
class CSomeClass
{
...
friend class CFriendCalss;
...
};
最后,您将开始实施您的方法:
void CFriendClass::SomeMethod( CSomeClass object) {...}
创建一些简单的示例来解决您可能遇到的一些语法问题可能是个好主意。
如果您决定练习,我会建议您创建具有两个值的类 CDot:x 和 y,并在创建非成员函数 double distance( CDot a, CDot b); 之后。这将计算从第一个点到第二个点的距离。
对于友元类,我建议您使用相同的类 CDot 及其友元类 CLineSegment 从两个 CDot 对象创建一个线段。
现在,我们将考虑友元类具有的几个属性。
第一个很容易理解。如果 A 类是 B 类的朋友,这并不意味着 B 类将是 A 类的朋友,无需一些额外的编码。如果你真的需要 A 也成为 B 的朋友,你也需要说明这一点。
下一个有趣的性质有时称为传递性。例如,让我们假设您面临三个类:A、B 和 C 类。
如果你有 B 作为 A 的朋友,你有 C 作为 B 的朋友,那么期望 C 成为 A 的朋友可能是合理的。这一次,你朋友的朋友不是你的朋友。正如您可能得出的结论,您需要声明 C 也是 A 的朋友。
友元修饰符示例代码——问题定义
为了解释朋友修饰符,我们将创建一个示例。这将说明如何重载运算符,我们还将说明如何使用 ostream 和 istream 作为对象,将数据从用户呈现和导入我们的类。
对于我们的练习,我们的任务是创建类 CComplexNumber。
- 只是为了刷新您的数学记忆,以下是复数的一些属性:
- 这个问题将帮助你解决这样的问题:ax*x + b*x + c =0。
- 复数有两部分:实数和虚数。该虚部是-1的平方根的倍数。
- 为此,它通常表示为:z = x + i*y。
- 除此之外,您还有复数和指数形式的极坐标形式。
友元修饰符示例代码 - 解决方案
以下是使用朋友修饰符解决我们问题的示例 C++ 代码。
#include <iostream>
using namespace std;
class CKomplexNumber
{
private:
double dX,dY;
public:
CKomplexNumber(const double x, const double y)
{dX=x;dY=y;}
CKomplexNumber(){;//This is not a smiley}
CKomplexNumber
operator+(const CKomplexNumber& z)
{
CKomplexNumber temp=*this;
temp.dX += z.dX; temp.dY += z.dY;
return temp;
}
friend ostream&
operator<<(ostream& out, const CKomplexNumber z);
friend istream&
operator>>(istream& in, CKomplexNumber& z);
};
ostream&
operator<<(ostream& out, const CKomplexNumber z)
{
cout<<"Complex number is"<<endl;
out<<z.dX<<" + "<<z.dY<<" i"<<endl;
return out;
}
istream&
operator>>(istream& in, CKomplexNumber& z)
{
cout<<"Imput real and imaginary part"<<endl;
in>>z.dX>>z.dY;
return in;
}
int
main(void)
{
CKomplexNumber Z1;
cout<<"First complex number is="<<endl;
cin>>Z1;
cout<<Z1;
CKomplexNumber Z2;
cout<<"Second complex number is="<<endl;
cin>>Z2;
cout<<Z2;
CKomplexNumber Z3;
cout<<"Third complex number is="<<endl;
cin>>Z3;
cout<<Z3;
CKomplexNumber Zr(0,0);
Zr = Z1 + Z2 + Z3;
cout<<Zr;
return EXIT_SUCCESS;
}
友元修饰符示例代码 - 说明
在上面的示例代码中:
- 在 CComplexNumber 类中,我们有用于描述复数值的数据。这是 dX 和 dY,它们是双数据类型。
- 我们也有构造函数,你甚至可以添加一些额外的构造函数和析构函数。
- 为了启用大多数逻辑语法,您将使用运算符 +。为了清楚起见,您不需要键入以下内容: Zr.AddComplexNumbers(Z1,Z2);
- 相反,如果你做这样简单的事情会更好:Zr = Z1 + Z2;
- 我们有两个重载运算符:“>>”和“<<”。你可以说我们不需要 set 和 get 方法,但它们也有它们的位置。或者,你可以说你使用了 get 和 set 方法很少。
- 现在我们将分析主函数中的代码。首先,我们实例化一个名为 Z1 的对象,然后我们输入它的值,即实部和虚部。
- 之后,Z1 呈现给用户。接下来的几个步骤非常相似,因此我们不需要再次深入细节。
最后,我们将这三个复数相加并将结果存储到 Zr 中,然后将结果呈现给用户。
对代码的建议改进
以下是您可以做的一些事情来改进上述代码以了解有关如何使用友元修饰符的更多信息:
- 通过支持复数的极坐标和指数形式来扩展解决方案。
- 接下来你可以做的是继承类,你也可以拥有三种类型的复数,然后尝试将三个类作为父类。您可以使用友元函数将这些复数从一种形式转换为另一种形式。
- 我们只重载了三个运算符:operator+、operator>> 和 operator<<。您也可以添加更多重载运算符。
- 现在,您可能会开始考虑:溢出、下溢和错误输入,因为您的代码可能会发生一些不好的事情,如果您希望在现实生活中使用您的类,这可能是我们大多数人的最终目标,你应该想办法让你的代码更健壮。
- 在相关说明中,您可能会发现这有助于使您的代码健壮:C 和 C++ 性能改进代码优化的 10 条提示
- 使用上述代码片段作为基础,创建一个用户友好的复数计算器。
与封装和继承的关系
在您了解了朋友修饰符的工作原理并开始创建实用规则之后,您可能会问自己它与封装有什么关系?
封装是OOP的主要原则之一。有些人可能认为朋友修饰符正在破坏 OOP 的概念。但它不会,它将允许需要的异常,这样它会保留封装,由于技术问题而产生的分歧最小。
有时把它想象成一个类的接口是好的。这就是为什么你可以说类在这种情况下有某种关系的原因。
将您的数据放在 public 修饰符下将是对封装起作用的示例。
你可能会问的另一个问题是:我是否从父类继承朋友?
我们已经解释了继承。在大多数情况下,您需要公共继承,这意味着您正在使用新功能扩展基类,这排除了私有成员。
这个问题的答案是否定的。我们不会从父类继承朋友。
- 点赞
- 收藏
- 关注作者
评论(0)