development

C ++에서 상속 된 우정을 허용하지 않는 이유는 무엇입니까?

big-blog 2020. 9. 16. 08:06
반응형

C ++에서 상속 된 우정을 허용하지 않는 이유는 무엇입니까?


C ++에서 우정이 적어도 선택적으로 상속되지 않는 이유는 무엇입니까? 나는 명백한 이유로 인해 전이성과 재 귀성이 금지된다는 것을 이해하지만 (단순한 FAQ 인용문 답변을 언급하기 위해서만이 말을합니다), virtual friend class Foo;퍼즐 라인을 따라 무언가가 부족하다는 것은 괴롭 힙니다. 이 결정의 역사적 배경을 아는 사람이 있습니까? 우정은 정말 몇 가지 모호한 존경할만한 용도로 사용 된 제한된 해킹 이었습니까?

명확히하기 위해 편집 : A의 자식이 B와 B와 자식 모두에 노출되는 것이 아니라 다음 시나리오에 대해 이야기 하고 있습니다. 친구 기능 등의 재정의에 대한 액세스 권한을 선택적으로 부여하는 것도 상상할 수 있습니다.

class A {
  int x;
  friend class B;
};

class B {
  // OK as per friend declaration above.
  void foo(A& a, int n) { a.x = n; }
};

class D : public B { /* can't get in A w/o 'friend class D' declaration. */ };

허용 대답은 :로키 상태 , 효과는 매우 엄격한 없다, 더 많거나 적은 friended했다 기본 클래스에서 보호 프록시 기능을함으로써 시뮬레이션 할 수 있습니다 필요 클래스 또는 가상 메서드 계층 구조에 우정을 부여하는가. 나는 상용구 프록시 (친구 기반이 효과적으로되는)의 필요성을 싫어하지만, 이것이 대부분의 시간 동안 오용 될 가능성이 더 높은 언어 메커니즘보다 선호되는 것으로 간주되었다고 생각합니다. 나는 아마도 Stroupstrup의 The Design and Evolution of C ++를 구입하고 읽을 때라고 생각합니다. 이런 유형의 질문에 대한 더 나은 통찰력을 얻기 위해 여기에서 충분한 사람들이 추천하는 것을 보았습니다.


내가 쓸 수 있기 때문에 Foo그 친구 Bar(따라서 신뢰 관계가 있습니다).

그러나 나는 파생 된 클래스를 작성하는 사람들을 신뢰 Bar합니까?
별로. 따라서 그들은 우정을 상속해서는 안됩니다.

클래스의 내부 표현이 변경되면 해당 표현에 종속 된 모든 항목을 수정해야합니다. 따라서 클래스의 모든 멤버와 클래스의 모든 친구는 수정이 필요합니다.

내부 표현 따라서 만약 Foo다음 수정은 Bar(친구 단단히 결합 있기 때문에 수정해야 BarFoo). 우정이 상속되면에서 파생 된 모든 클래스 Bar도 밀접하게 바인딩 Foo되므로 Foo의 내부 표현이 변경 되면 수정이 필요합니다 . 하지만 파생 된 유형에 대한 지식이 없습니다 (나도 마찬가지입니다. 다른 회사에서 개발할 수도 있음). 따라서 Foo에서 파생 된 모든 클래스를 수정할 수 없기 때문에 코드베이스에 주요 변경 사항이 도입되므로 변경할 수 없습니다 Bar.

따라서 우정이 물려받은 경우 실수로 클래스를 수정할 수있는 기능에 제한이 있습니다. 이는 기본적으로 공용 API의 개념을 쓸모 없게 렌더링하므로 바람직하지 않습니다.

참고 :의 자식은 을 사용하여 Bar액세스 할 수 있습니다 . 메서드를 protected로 설정하면 됩니다. 그러면의 자식은 부모 클래스를 통해 호출 하여 액세스 할 수 있습니다 .FooBarBarBarFoo

이것이 당신이 원하는 것입니까?

class A
{
    int x;
    friend class B;
};

class B
{
    protected:
       // Now children of B can access foo
       void foo(A& a, int n) { a.x = n; }
};

class D : public B
{
    public:
        foo(A& a, int n)
        {
            B::foo(a, n + 5);
        }
};

C ++에서 우정이 적어도 선택적으로 상속되지 않는 이유는 무엇입니까?

첫 번째 질문에 대한 답은 "아버지의 친구가 귀하의 개인 정보에 액세스 할 수 있습니까?"라는 질문에 있다고 생각합니다.


friended 클래스는 접근 자 함수를 통해 친구를 노출 한 다음이를 통해 액세스 권한을 부여 할 수 있습니다.

class stingy {
    int pennies;
    friend class hot_girl;
};

class hot_girl {
public:
    stingy *bf;

    int &get_cash( stingy &x = *bf ) { return x.pennies; }
};

class moocher {
public: // moocher can access stingy's pennies despite not being a friend
    int &get_cash( hot_girl &x ) { return x.get_cash(); }
};

이를 통해 선택적 전이성보다 더 미세한 제어가 가능합니다. 예를 들어, 런타임 제한 액세스 프로토콜을 적용하거나 시행 할 get_cash수 있습니다 protected.


C ++ 표준, 섹션 11.4 / 8

우정은 상속되거나 전이되지 않습니다.

If friendship would be inherited, then a class that wasn't meant to be a friend would suddenly have access to your class internals and that violates encapsulation.


Because it's just unnecessary.

The usage of the friend keyword is itself suspicious. In term of coupling it's the worst relationship (way ahead of inheritance and composition).

Any change to the internals of a class have a risk to impact the friends of this class... do you really want an unknown number of friends ? You would not even be able to list them if those who inherit from them could be friends also, and you would run in the risk of breaking your clients code each time, surely this is not desirable.

I freely admit that for homework/pet projects dependency is often a far away consideration. On small size projects it doesn't matter. But as soon as several persons work on the same project and this grows into the dozens of thousands of lines you need to limit the impact of changes.

This bring a very simple rule:

Changing the internals of a class should only affect the class itself

Of course, you'll probably affect its friends, but there are two cases here:

  • friend free function: probably more of a member function anyway (I am think std::ostream& operator<<(...) here, which is not a member purely by accident of the language rules
  • friend class ? you don't need friend classes on real classes.

I would recommend the use of the simple method:

class Example;

class ExampleKey { friend class Example; ExampleKey(); };

class Restricted
{
public:
  void forExampleOnly(int,int,ExampleKey const&);
};

This simple Key pattern allows you to declare a friend (in a way) without actually giving it access to your internals, thus isolating it from changes. Furthermore it allows this friend to lend its key to trustees (like children) if required.


A guess: If a class declares some other class/function as a friend, it's because that second entity needs privileged access to the first. What use is there in granting the second entity privileged access to an arbitrary number of classes derived from the first?


A derived class can inherit only something, which is 'member' of the base. A friend declaration is not a member of the befriending class.

$11.4/1- "...The name of a friend is not in the scope of the class, and the friend is not called with the member access operators (5.2.5) unless it is a member of another class."

$11.4 - "Also, because the base-clause of the friend class is not part of its member declarations, the base-clause of the friend class cannot access the names of the private and protected members from the class granting friendship."

and further

$10.3/7- "[Note: the virtual specifier implies membership, so a virtual function cannot be a nonmember (7.1.2) function. Nor can a virtual function be a static member, since a virtual function call relies on a specific object for determining which function to invoke. A virtual function declared in one class can be declared a friend in another class. ]"

Since the 'friend' is not a member of the base class in the first place, how can it be inherited by the derived class?


Friend function in a class assigns the extern property to the function. i.e. extern means that the function has been declared and defined somewhere out of the class.

Hence it means friend function is not a member of a class. So the inheritance only allows you to inherit the properties of a class not external things. And also if inheritance is allowed for friend functions, then a third party class inheriting.


Friend is good in inheritance like style interface for container But for me, as the first say, C++ lack the propagatable inheritance

class Thing;

//an interface for Thing container's
struct IThing {
   friend Thing;
   protected:
       int IThing_getData() = 0;
};

//container for thing's
struct MyContainer : public IThing {
    protected: //here is reserved access to Thing
         int IThing_getData() override {...}
};

struct Thing {
    void setYourContainer(IThing* aContainerOfThings) {
        //access to unique function in protected area 
        aContainerOfThings->IThing_getData(); //authorized access
    }
};

struct ChildThing : public Thing {
    void doTest() {
        //here the lack of granularity, you cannot access to the container.
        //to use the container, you must implement all 
        //function in the Thing class
        aContainerOfThings->IThing_getData(); //forbidden access
    }
};

For me the problem of C++ is the lack of very good granularity to control all access from anywhere for anything :

friend Thing can become friend Thing.* to grant access to all child of Thing

And more, friend [named area] Thing.* to grant access for a precise are in the Container class via special named area for the friend.

Ok stop the dream. But now, you know an interesting usage of friend.

In another order, you can also found interesting to known all class are friendly with self. In other word, a class instance can call all
members of another instance of same name without restriction:

class Object {
     private:
         void test() {}
     protected:
         void callAnotherTest(Object* anotherObject) {
             //private, but yes you can call test() from 
             //another object instance
             anotherObject)->test(); 
         }
};

Simple logic : 'I have a friend Jane. Just because we became friends yesterday does not make all of her friends mine.'

I still need to approve those individual friendships, and the level of trust would be accordingly.

참고URL : https://stackoverflow.com/questions/3561648/why-does-c-not-allow-inherited-friendship

반응형