roo*_*roo 343 c++ oop encapsulation friend
我一直在阅读C++常见问题,并对该friend声明感到好奇.我个人从未使用它,但我有兴趣探索这种语言.
什么是使用的好例子friend?
阅读常见问题更长一点我喜欢<< >>运算符重载的想法,并添加为这些类的朋友.但是我不确定这是如何不破坏封装的.这些例外何时可以保持在OOP的严格范围内?
And*_*ant 325
首先(IMO)不听那些说friend没用的人.它是有益的.在许多情况下,您将拥有数据或功能不可公开的对象.对于具有许多作者的大型代码库尤其如此,这些作者可能只是表面上熟悉不同的领域.
朋友说明符有其他选择,但通常它们很麻烦(cpp级别的具体类/掩码类型的定义)或者不是万无一失的(注释或函数名称约定).
在答案上;
该friend说明符可以让朋友语句类中指定的类访问受保护的数据或功能.例如,在下面的代码中,任何人都可以询问孩子的姓名,但只有母亲和孩子可以更改姓名.
您可以通过考虑更复杂的类(如Window)来进一步采用这个简单的示例.很可能一个Window将有许多不应公开访问的函数/数据元素,但是相关类(例如WindowManager)需要ARE.
class Child
{
//Mother class members can access the private parts of class Child.
friend class Mother;
public:
string name( void );
protected:
void setName( string newName );
};
Run Code Online (Sandbox Code Playgroud)
Dae*_*min 154
在工作中,我们广泛使用朋友来测试代码.这意味着我们可以为主应用程序代码提供适当的封装和信息隐藏.但是我们也可以使用单独的测试代码来使用朋友来检查内部状态和数据以进行测试.
我只想说我不会将friend关键字用作您设计的重要组成部分.
Joh*_*itb 92
该friend关键字有许多好用途.以下是我立即可见的两种用法:
朋友定义允许在类范围内定义一个函数,但该函数不会被定义为成员函数,而是作为封闭命名空间的自由函数,并且除了参数依赖查找之外不会正常显示.这使得它对运算符重载特别有用:
namespace utils {
class f {
private:
typedef int int_type;
int_type value;
public:
// let's assume it doesn't only need .value, but some
// internal stuff.
friend f operator+(f const& a, f const& b) {
// name resolution finds names in class-scope.
// int_type is visible here.
return f(a.value + b.value);
}
int getValue() const { return value; }
};
}
int main() {
utils::f a, b;
std::cout << (a + b).getValue(); // valid
}
Run Code Online (Sandbox Code Playgroud)
有时,您发现策略需要访问派生类:
// possible policy used for flexible-class.
template<typename Derived>
struct Policy {
void doSomething() {
// casting this to Derived* requires us to see that we are a
// base-class of Derived.
some_type const& t = static_cast<Derived*>(this)->getSomething();
}
};
// note, derived privately
template<template<typename> class SomePolicy>
struct FlexibleClass : private SomePolicy<FlexibleClass> {
// we derive privately, so the base-class wouldn't notice that,
// (even though it's the base itself!), so we need a friend declaration
// to make the base a friend of us.
friend class SomePolicy<FlexibleClass>;
void doStuff() {
// calls doSomething of the policy
this->doSomething();
}
// will return useful information
some_type getSomething();
};
Run Code Online (Sandbox Code Playgroud)
你会在这个答案中找到一个非人为的例子.使用它的另一个代码就在这个答案中.CRTP基类会转换它的this指针,以便能够使用data-member-pointers访问派生类的数据字段.
Kon*_*lph 41
@roo:封装不会在这里被破坏,因为类本身决定谁可以访问其私有成员.如果这可能是在课外引起的,那么封装只会被打破,例如,如果你operator <<宣称"我是班上的朋友" foo.
friend替换使用public,而不是使用private!
实际上,C++ FAQ 已经解决了这个问题.
Mar*_*son 27
规范的例子是重载operator <<.另一个常见用途是允许帮助者或管理员类访问您的内部.
以下是我听说过C++朋友的一些指导原则.最后一个特别值得纪念.
jal*_*alf 16
编辑:读取faq更长一点我喜欢<< >>运算符重载的想法并添加为这些类的朋友,但是我不知道这怎么不破坏封装
它将如何打破封装?
当您允许不受限制地访问数据成员时,您会破坏封装.考虑以下类:
class c1 {
public:
int x;
};
class c2 {
public:
int foo();
private:
int x;
};
class c3 {
friend int foo();
private:
int x;
};
Run Code Online (Sandbox Code Playgroud)
c1是明显不封装.任何人都可以阅读和修改x它.我们无法强制执行任何类型的访问控制.
c2显然是封装的.没有公共访问权限x.您所能做的就是调用foo函数,该函数对类执行一些有意义的操作.
c3?是不是封装了?它是否允许不受限制的访问x?它是否允许未知功能访问?
不.它只允许一个函数访问类的私有成员.就像c2那样.就像c2,具有访问权限的一个函数不是"一些随机的,未知的函数",而是"类定义中列出的函数".就像c2,我们可以通过查看类定义,查看谁有权访问的完整列表.
那么这个封装的确切程度如何呢?相同数量的代码可以访问该类的私有成员.而且大家谁有权访问被列在类的定义.
friend不破坏封装.这让一些Java程序员感到不舒服,因为当他们说"OOP"时,他们实际上意味着 "Java".当他们说"封装"时,他们并不是说"私人成员必须受到保护以免受任意访问",而是"只有能够访问私人成员的Java类才是类成员",尽管这完全是胡说八道.几个原因.
首先,如图所示,它太局限了.没有理由不允许朋友方法做同样的事情.
其次,它是不是限制性不够.考虑第四类:
class c4 {
public:
int getx();
void setx(int x);
private:
int x;
};
Run Code Online (Sandbox Code Playgroud)
根据上述Java心态,这是完全封装的. 然而,它绝对允许任何人阅读和修改x.这怎么有意义呢?(提示:它没有)
底线:封装是关于能够控制哪些功能可以访问私有成员.它不是关于这些函数的定义的确切位置.
mac*_*llt 10
另一个常见的安德鲁例子,可怕的代码对联
parent.addChild(child);
child.setParent(parent);
Run Code Online (Sandbox Code Playgroud)
如果两条线总是以一致的顺序一起完成而不是担心,您可以将这些方法设为私有,并使用友元函数来强制执行一致性:
class Parent;
class Object {
private:
void setParent(Parent&);
friend void addChild(Parent& parent, Object& child);
};
class Parent : public Object {
private:
void addChild(Object& child);
friend void addChild(Parent& parent, Object& child);
};
void addChild(Parent& parent, Object& child) {
if( &parent == &child ){
wetPants();
}
parent.addChild(child);
child.setParent(parent);
}
Run Code Online (Sandbox Code Playgroud)
换句话说,您可以保持公共接口更小,并强制执行跨越友元函数中的类和对象的不变量.
您使用私有/受保护/公共权限控制成员和功能的访问权限?所以假设这3个级别中的每个级别的想法都很明确,那么应该很清楚我们遗漏了一些东西......
例如,成员/函数声明受保护是非常通用的.你说这个功能对每个人来说都是遥不可及的(当然除了继承的孩子).但是例外呢?每个安全系统都可以让你拥有某种类型的"白名单"吗?
所以朋友可以让你灵活地拥有坚如磐石的物体隔离,但允许为你认为合理的东西创造一个"漏洞".
我想人们说不需要它,因为总有一种设计可以没有它.我认为它类似于对全局变量的讨论:你永远不应该使用它们,总有一种方法可以不用它们......但实际上,你会看到最终成为(几乎)最优雅方式的情况. ..我认为这与朋友的情况相同.
除了让您在不使用设置功能的情况下访问成员变量之外,它实际上没有任何好处
好吧,这不是看待它的方式.这个想法是控制世界卫生组织可以访问什么,设置功能与否有关.
C++的创造者说这并没有违反任何封装原则,我会引用他的话:
“朋友”是否违反封装? 不,不是的。“朋友”是授予访问权限的显式机制,就像成员身份一样。您不能(在符合标准的程序中)在不修改类源的情况下授予自己对类的访问权限。
是不是很清楚...
| 归档时间: |
|
| 查看次数: |
162834 次 |
| 最近记录: |