C++ 允许“朋友”类仅访问某些私有成员

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16055616/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:02:28  来源:igfitidea点击:

Allowing a "friend" class to access only some private members

c++friend

提问by Archer

Suppose I have three C++ classes FooA, FooB and FooC.

假设我有三个 C++ 类 FooA、FooB 和 FooC。

FooA has an member function named Hello, I want to call this function in class FooB, but I don't want class FooC be able to call it. The best way I can figure out to realize this is to declare FooB as a friend class of FooA. But as long as I do this, allFooA's private and protected members will be exposed which is quite unacceptable to me.

FooA 有一个名为 的成员函数Hello,我想在类 FooB 中调用此函数,但我不希望类 FooC 能够调用它。我能想出实现这一点的最好方法是将 FooB 声明为 FooA 的朋友类。但是只要我这样做,所有FooA 的私有成员和受保护成员都会暴露出来,这对我来说是非常不可接受的。

So, I wanna know if there is any mechanism in C++(03 or 11) better than friendclass which can solve this dilemma.

所以,我想知道 C++(03 或 11)中是否有比friend类更好的机制可以解决这个难题。

And I assume it will be nice if the following syntax is possible:

我认为如果可以使用以下语法会很好:

class FooA
{
private friend class FooB:
    void Hello();
    void Hello2();
private:
    void Hello3();
    int m_iData;
};

class FooB
{
    void fun()
    {
        FooA objA;
        objA.Hello()  // right
        objA.Hello2() // right
        objA.Hello3() // compile error
        ojbA.m_iData = 0; // compile error
    }
};

class FooC
{
    void fun()
    {
        FooA objA;
        objA.Hello()  // compile error
        objA.Hello2() // compile error
        objA.Hello3() // compile error
        ojbA.m_iData = 0; // compile error
    }
};

采纳答案by Steve Jessop

There's nothing to make a class a friend of one specific function, but you can make FooBa friend of a "key" class with private constructor, and then have FooA::Hellotake that class as an ignored parameter. FooCwill be unable to provide the parameter and hence can't call Hello:

没有什么可以让一个类成为一个特定函数的朋友,但是你可以让FooB一个带有私有构造函数的“关键”类成为朋友,然后FooA::Hello将该类作为一个被忽略的参数。FooC将无法提供参数,因此无法调用Hello

Is this key-oriented access-protection pattern a known idiom?

这种面向密钥的访问保护模式是一种已知的习惯用法吗?

回答by ForEveR

I think you can use Attorney-Clienthere.

我认为您可以在这里使用“律师-客户”

In your case example should be like this

在你的情况下,例子应该是这样的

class FooA
{
private:
    void Hello();
    void Hello2();
    void Hello3();
    int m_iData;

    friend class Client;
};

class Client
{
private:
   static void Hello(FooA& obj)
   {
      obj.Hello();
   }
   static void Hello2(FooA& obj)
   {
      obj.Hello2();
   }
   friend class FooB;
};

class FooB
{
    void fun()
    {
        FooA objA;
        Client::Hello(objA);  // right
        Client::Hello2(objA); // right
        //objA.Hello3() // compile error
        //ojbA.m_iData = 0; // compile error
    }
};

class FooC
{
    void fun()
    {
        /*FooA objA;
        objA.Hello()  // compile error
        objA.Hello2() // compile error
        objA.Hello3() // compile error
        ojbA.m_iData = 0; // compile error*/
    }
};

回答by Lightness Races in Orbit

No, and this is not really a limitation. To my mind, the limitation is that friend— a blunt weapon for hacking around design flaws — exists in the first place.

不,这并不是真正的限制。在我看来,局限性在于friend——一种绕过设计缺陷的钝器——首先存在。

Your class FooAhas no business knowing about FooBand FooCand "which one should be able to use it". It should have a public interface, and not carewho can use it. That's the point of the interface! Calling functions within that interface should alwaysleave the FooAin a nice, safe, happy, consistent state.

你的类FooA没有业务寂寂FooBFooC和“这应该能够使用它。” 它应该有一个公共接口,而不关心谁可以使用它。这就是界面的重点!该界面中调用函数应该始终保留FooA在一个不错的,安全的,幸福的,一致的状态。

And if your concern is that you might accidentally use the FooAinterface from somewhere you didn't mean to, well, simply don't do that; C++ is not a language suited to protecting against these kinds of user errors. Your test coverage should suffice in this case.

如果您担心您可能会在无意中意外使用该FooA界面,那么请不要这样做;C++ 不是一种适合防止此类用户错误的语言。在这种情况下,您的测试覆盖率应该足够了。

Strictly speaking, I'm sure you can obtain the functionality you're after with some ghastly complicated "design pattern" but, honestly, I wouldn't bother.

严格来说,我相信你可以通过一些极其复杂的“设计模式”获得你想要的功能,但老实说,我不会打扰。

If this is a problem for the semantics of your program's design, then I politely suggest that your design has a flaw.

如果这是您程序设计语义的问题,那么我礼貌地建议您的设计存在缺陷。

回答by Jerome Baldridge

The safest solution is to use another class as the "go-between" for your two classes, rather than make one of them a friend.One way to do this is suggested in the answer by @ForEveR, but you can also do some searching about proxy classes and other design patterns that can apply.

最安全的解决方案是使用另一个类作为两个类的“friend.中间人”,而不是让其中一个成为@ForEveR 的答案中建议的一种方法,但您也可以对代理进行一些搜索类和其他可以应用的设计模式。

回答by rolevax

You can partially expose a class's interfaces to a specified client by inherit it from an interface class.

您可以通过从接口类继承类来部分地向指定的客户端公开类的接口。

class FooA_for_FooB
{
public:
    virtual void Hello() = 0;
    virtual void Hello2() = 0;
};

class FooA : public FooA_for_FooB
{
private: /* make them private */
    void Hello() override;
    void Hello2() override;
private:
    void Hello3();
    int m_iData;
};

class FooB
{
    void fun()
    {
        FooA objA;
        FooA_for_FooB &r = objA;
        r.Hello()  // right
        r.Hello2() // right
        objA.Hello3() // compile error
        objA.m_iData = 0; // compile error
    }
};

class FooC
{
    void fun()
    {
        FooA objA;
        objA.Hello()  // compile error
        objA.Hello2() // compile error
        objA.Hello3() // compile error
        objA.m_iData = 0; // compile error
    }
};

Here access control is enhanced by the base class FooA_for_FooB. By a reference of type FooA_for_FooB, FooBcan access the members defined within FooA_for_FooB. However, FooCcannot access those members since they have been override as private members in FooA. Your purpose can be achieved by not using the type FooA_for_FooBwithin FooC, or any other places except FooB, which can be kept without paying much attention.

在这里,基类增强了访问控制FooA_for_FooB。通过引用类型FooA_for_FooBFooB可以访问其中定义的成员FooA_for_FooB。但是,FooC无法访问这些成员,因为它们已在FooA. 你的目标可以通过不使用类型来实现FooA_for_FooBFooC,或任何其他地方,除了FooB,这可以保持不十分重视。

This approach needs no friend, making things simple.

这种方法不需要friend,使事情变得简单。

A similar thing can be done by making everything private in a base class, and selectively wrap-and-expose some of the members as public in the derived class. This approach may sometimes require ugly downcast, though. (Because the base class will become the "currency" among the whole program.)

类似的事情可以通过将基类中的所有内容设为私有,并有选择地将派生类中的某些成员包装并公开为公共成员来完成。但是,这种方法有时可能需要丑陋的沮丧。(因为基类会成为整个程序中的“货币”。)

回答by user3737631

You'll need inheritance. Try this:

你需要继承。尝试这个:

// _ClassA.h
class _ClassA
{
  friend class ClassA;
private:
  //all your private methods here, accessible only from ClassA and _ClassA.
}

// ClassA.h
class ClassA: _ClassA
{
  friend class ClassB;
private:
  //all_your_methods
}

This way you have: ClassBis the only one to be able to use ClassA. ClassBcannot access _ClassAmethods, that are private.

这样您就拥有: ClassB是唯一能够使用ClassA. ClassB无法访问_ClassA私有的方法。

回答by Yochai Timmer

The whole idea of friendis to expose your class to a friend.

整个想法friend是将您的课程暴露给朋友。

There are 2 ways you could be more specific about what you expose:

您可以通过两种方式更具体地了解您所公开的内容:

  1. Inherit from FooA, that way only protected and public methods are exposed.

  2. Only befriend a certain method, that way only that method will have access:

  1. 继承自FooA,这样只会公开受保护和公共方法。

  2. 只与某个方法成为朋友,这样只有那个方法才能访问:

.

.

 friend void FooB::fun();