C++ 您应该在何时使用';朋友';在C++;?
我一直在通读这份声明,对这份声明感到好奇。我个人从未使用过它,但是我对探索这种语言感兴趣 使用C++ 您应该在何时使用';朋友';在C++;?,c++,oop,encapsulation,friend,C++,Oop,Encapsulation,Friend,我一直在通读这份声明,对这份声明感到好奇。我个人从未使用过它,但是我对探索这种语言感兴趣 使用朋友的好例子是什么 阅读FAQ的时间再长一点,我喜欢操作符重载的想法,并将其添加为这些类的朋友。然而,我不确定这如何不破坏封装。这些异常何时能保持在OOP的严格范围内?在为类实现树算法时,教授给我们的框架代码将树类作为节点类的朋友 除了让您不使用设置函数就访问成员变量之外,它实际上没有任何用处。首先(IMO)不要听那些说friend没有用处的人说。这是有用的。在许多情况下,您将拥有数据或功能不打算公开
朋友的好例子是什么
阅读FAQ的时间再长一点,我喜欢
操作符重载的想法,并将其添加为这些类的朋友。然而,我不确定这如何不破坏封装。这些异常何时能保持在OOP的严格范围内?在为类实现树算法时,教授给我们的框架代码将树类作为节点类的朋友
除了让您不使用设置函数就访问成员变量之外,它实际上没有任何用处。首先(IMO)不要听那些说friend
没有用处的人说。这是有用的。在许多情况下,您将拥有数据或功能不打算公开的对象。这一点在大型代码库中尤其明显,因为许多作者可能只对不同领域略知一二
友元说明符有多种替代方法,但它们通常比较麻烦(cpp级别的具体类/屏蔽的typedef)或不简单(注释或函数名约定)
关于答案
friend
说明符允许指定类访问生成friend语句的类中受保护的数据或功能。例如,在下面的代码中,任何人都可以询问孩子的姓名,但只有母亲和孩子可以更改姓名
您可以通过考虑更复杂的类(如窗口),进一步了解这个简单的示例。一个窗口很可能有许多不应该公开访问的函数/数据元素,但相关类(如WindowManager)需要这些元素
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 );
};
树示例是一个非常好的示例:
在几个不同的类中实现一个对象而没有
有继承关系的
也许你还需要一个构造函数来保护它并强制它
人们使用你的“朋友”工厂
。。。好吧,坦白说,你可以不使用它。你使用私有/受保护/公共权限控制成员和函数的访问权限?
因此,假设这三个层次中的每一个都是清晰的,那么应该很清楚我们遗漏了什么
例如,将成员/函数声明为protected是非常通用的。您的意思是每个人都无法使用此功能(当然继承的孩子除外)。但是例外情况呢?每个安全系统都会让你有某种类型的“白名单”,对吗
因此,friend让您可以灵活地进行坚固的对象隔离,但允许为您认为合理的事情创建“漏洞”
我想人们会说不需要它,因为总有一种设计可以不用它。我认为这类似于对全局变量的讨论:你永远不应该使用它们,总有一种方法可以不用它们……但在现实中,你会看到这样的情况(几乎)最优雅的方式…我认为朋友也是如此
除了让您不使用设置函数就访问成员变量之外,它实际上没有任何用处
嗯,这并不是正确的看法。
其思想是控制谁可以访问什么,有没有设置函数与此无关。典型的例子是重载操作符:这里没有破坏封装,因为类本身决定谁可以访问其私有成员。只有当这可能是由类外引起的,例如。如果您的操作符您可以遵守最严格和最纯粹的OOP原则,并确保任何类的数据成员都没有访问器,因此所有对象都必须是唯一可以了解其数据的对象,唯一的操作方法是通过间接消息,即方法
<> P>但即使C++有一个强的>内部<强>可见性关键字,java也有其默认的<>强>包可访问级别。对于C++,它实际上通过更接近于OOP的理想,通过指定<强> > < <强> >其他类和<强> > <强>其他类,从而最小化可视性到类的妥协。我们可以看到它
<>我并不真正使用C++,但是如果C语言有朋友,我会代替汇编全局的<强>内部<强>修饰符,实际上我使用了很多。它并不真正地破坏包内,因为在.NET<强>中的部署单位是一个程序集。
但是,C++有一个强的>国际化的Visualto to /Stand属性(其他程序集),它的行为就像一个交叉组件<强>朋友>强>机制。微软使用这个工具来设计可视化设计器程序集。
< P>。
朋友能知道我的一切吗
更新:我发现这个关于“朋友”关键字的有价值的答案
“朋友”是一种明确的授予访问权限的机制,就像成员资格一样
在TDD中,我多次使用C++中的“朋友”关键字。
不,这只是单向的友谊:`(我在创建类时使用的一个特定实例是friend
。通过friend
关键字,我可以创建一个访问器函数,它比在类上始终使用“GetInstance()”方法更简洁
/////////////////////////
// Header file
class MySingleton
{
private:
// Private c-tor for Singleton pattern
MySingleton() {}
friend MySingleton& GetMySingleton();
}
// Accessor function - less verbose than having a "GetInstance()"
// static function on the class
MySingleton& GetMySingleton();
/////////////////////////
// Implementation file
MySingleton& GetMySingleton()
{
static MySingleton theInstance;
return theInstance;
}
// friend functions
#include <iostream>
using namespace std;
class Rectangle {
int width, height;
public:
Rectangle() {}
Rectangle (int x, int y) : width(x), height(y) {}
int area() {return width * height;}
friend Rectangle duplicate (const Rectangle&);
};
Rectangle duplicate (const Rectangle& param)
{
Rectangle res;
res.width = param.width*2;
res.height = param.height*2;
return res;
}
int main () {
Rectangle foo;
Rectangle bar (2,3);
foo = duplicate (bar);
cout << foo.area() << '\n';
return 0;
}
关于operator>没有很好的理由让这些操作符成为朋友。的确,它们不应该是成员函数,但它们也不需要成为朋友
最好的方法是创建公共打印(ostream&)和读取(istream&)函数
parent.addChild(child);
child.setParent(parent);
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);
}
class MyFoo
{
private:
static void callback(void * data, void * clientData);
void localCallback();
...
};
class MyFoo
{
friend void callback(void * data, void * callData);
void localCallback();
}
class MyFooPrivate;
class MyFoo
{
friend class MyFooPrivate;
public:
MyFoo();
// Public stuff
private:
MyFooPrivate _private;
// Other private members as needed
};
class MyFooPrivate
{
public:
MyFoo *owner;
// Your complexity here
};
MyFoo::MyFoo()
{
this->_private->owner = this;
}
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
}
// 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();
};
template<typename T>
class FriendIdentity {
public:
typedef T me;
};
/**
* A class to get access to protected stuff in unittests. Don't use
* directly, use friendMe() instead.
*/
template<class ToFriend, typename ParentClass>
class Friender: public ParentClass
{
public:
Friender() {}
virtual ~Friender() {}
private:
// MSVC != GCC
#ifdef _MSC_VER
friend ToFriend;
#else
friend class FriendIdentity<ToFriend>::me;
#endif
};
/**
* Gives access to protected variables/functions in unittests.
* Usage: <code>friendMe(this, someprotectedobject).someProtectedMethod();</code>
*/
template<typename Tester, typename ParentClass>
Friender<Tester, ParentClass> &
friendMe(Tester * me, ParentClass & instance)
{
return (Friender<Tester, ParentClass> &)(instance);
}
friendMe(this, someClassInstance).someProtectedFunction();
class c1 {
public:
int x;
};
class c2 {
public:
int foo();
private:
int x;
};
class c3 {
friend int foo();
private:
int x;
};
class c4 {
public:
int getx();
void setx(int x);
private:
int x;
};
class Fred;
class FredBase {
private:
friend class Fred;
FredBase() { }
};
class Fred : private virtual FredBase {
public:
...
};
Point p;
cout << p;
friend ostream& operator<<(ostream& output, const Point& p);
class A
{
public:
void need_your_data(B & myBuddy)
{
myBuddy.take_this_name(name_);
}
private:
string name_;
};
class B
{
public:
void print_buddy_name(A & myBuddy)
{
myBuddy.need_your_data(*this);
}
void take_this_name(const string & name)
{
cout << name;
}
};
class Beer {
public:
friend bool equal(Beer a, Beer b);
private:
// ...
};
class Birds {
public:
friend Birds operator +(Birds, Birds);
private:
int numberInFlock;
};
Birds operator +(Birds b1, Birds b2) {
Birds temp;
temp.numberInFlock = b1.numberInFlock + b2.numberInFlock;
return temp;
}
// friend functions
#include <iostream>
using namespace std;
class Rectangle {
int width, height;
public:
Rectangle() {}
Rectangle (int x, int y) : width(x), height(y) {}
int area() {return width * height;}
friend Rectangle duplicate (const Rectangle&);
};
Rectangle duplicate (const Rectangle& param)
{
Rectangle res;
res.width = param.width*2;
res.height = param.height*2;
return res;
}
int main () {
Rectangle foo;
Rectangle bar (2,3);
foo = duplicate (bar);
cout << foo.area() << '\n';
return 0;
}
1.Overload "operator <<()" function in "ostream" class.
2.Overload "operator<<()" function in "Point" class.
1.Using ostream object cout.As: cout.operator<<(Pointobj) (form ostream class).
2.Call without an object.As: operator<<(cout, Pointobj) (from Point class).
class ClubHouse {
public:
friend class VIPMember; // VIP Members Have Full Access To Class
private:
unsigned nonMembers_;
unsigned paidMembers_;
unsigned vipMembers;
std::vector<Member> members_;
public:
ClubHouse() : nonMembers_(0), paidMembers_(0), vipMembers(0) {}
addMember( const Member& member ) { // ...code }
void updateMembership( unsigned memberID, Member::MembershipType type ) { // ...code }
Amenity getAmenity( unsigned memberID ) { // ...code }
protected:
void joinVIPEvent( unsigned memberID ) { // ...code }
}; // ClubHouse
class Member {
public:
enum MemberShipType {
NON_MEMBER_PAID_EVENT, // Single Event Paid (At Door)
PAID_MEMBERSHIP, // Monthly - Yearly Subscription
VIP_MEMBERSHIP, // Highest Possible Membership
}; // MemberShipType
protected:
MemberShipType type_;
unsigned id_;
Amenity amenity_;
public:
Member( unsigned id, MemberShipType type ) : id_(id), type_(type) {}
virtual ~Member(){}
unsigned getId() const { return id_; }
MemberShipType getType() const { return type_; }
virtual void getAmenityFromClubHouse() = 0
};
class NonMember : public Member {
public:
explicit NonMember( unsigned id ) : Member( id, MemberShipType::NON_MEMBER_PAID_EVENT ) {}
void getAmenityFromClubHouse() override {
Amenity = ClubHouse::getAmenity( this->id_ );
}
};
class PaidMember : public Member {
public:
explicit PaidMember( unsigned id ) : Member( id, MemberShipType::PAID_MEMBERSHIP ) {}
void getAmenityFromClubHouse() override {
Amenity = ClubHouse::getAmenity( this->id_ );
}
};
class VIPMember : public Member {
public:
friend class ClubHouse;
public:
explicit VIPMember( unsigned id ) : Member( id, MemberShipType::VIP_MEMBERSHIP ) {}
void getAmenityFromClubHouse() override {
Amenity = ClubHouse::getAmenity( this->id_ );
}
void attendVIPEvent() {
ClubHouse::joinVIPEvent( this->id );
}
};
class Amenity{};