class C{
  friend class F;
  private:
        fct1(){}
        fct2(){}
        fct3(){}
  public:
        fct_for_everyone(){}
};

class F{
};

F is a friend of C, so it has access to fct1,fct2,fct3.
But in real life, friendship has limits! You don't want to reveal everything! So is there a way in C++ to limit the frienships to specific data/functions?
For example, could F be granted access only to fc1 and fct2 but not to fct3.
Here is a way that seems to work:

class C{
  protected:
        fct1(){}
        fct2(){}
  private:
        fct3(){}
  public:
        fct_for_everyone(){}
};

class R:private C{
  friend F;
}
class F{
};

Here F has access to only fct1 and fct2.
But this is somewhat clumsy and limited. You could not have another friend F2 with other access rights at the same time.
Does anyone has a brilliant (and simple!) way to selectively control access by giving different rights to different friends?

Recommended Answers

All 17 Replies

>>Here F has access to only fct1 and fct2.
No it doesn't. Because you used private inheritance, it should only have access to the private function R::C::fct_for_everyone(). R doesn't even have access to C::fct1(), C::fct2(), or C::fct3() because they have "higher" access than private (which technically doesn't exist, which essentially makes them not exist). What would make you think a friend of R would be able to access them if R itself can't (excepting for Class F also being a friend of Class C, but that would require different syntax based on Class C instead of Class R)?

If you had used public inheritance, F would have access to R::C::fct1(), R::C::fct2(), and R::C::fct_for_everyone().

Yes it does! (And my compiler does agree too!)
It does because fct1 and fct2 are "protected" in class C.
The private inheritance of C in R just means that others cannot access to it unless they are a friend of R.
And because F is a friend of R it can access the "private" portion of R with includes the protected (inherited) part of C.

:confused:
I can't explain that. It's not logical to me. I'm getting similar results on 2 different compilers (VC++2008 & mingw). The relationship between R and C is behaving as expected, but F seems to be bypassing all the rules.

How can a friend of a derived class have greater access to the base class than the derived class?

If I use this code:

#include <iostream>

class C{
  protected:
    void fct1(){ std::cout << "In C::fct1()" << std::endl; }
    void fct2(){ std::cout << "In C::fct2()" << std::endl; }
  private:
    void fct3(){ std::cout << "In C::fct3()" << std::endl; }
  public:
    void fct_for_everyone(){ std::cout << "In C::fct_for_everyone()" << std::endl; }
};

class R : private C {
public:
  void CallCFunctions() {
    C someC;
    std::cout << "In R::CallCFunctions()...\n";
    std::cout << "Calling C::fct1()...\n";
    someC.fct1();
    std::cout << "Calling C::fct2()...\n";
    someC.fct2();
    std::cout << "Calling C::fct3()...\n";
    someC.fct3();
    std::cout << "Calling C::fct_for_everyone()...\n";
    someC.fct_for_everyone();
  }
};

int main() {
  R someR;
  someR.CallCFunctions();

  return 0;
}

I get:

main1.cpp(20) : error C2248: 'C::fct1' : cannot access private member declared in class 'C'
1> main1.cpp(5) : see declaration of 'C::fct1'
1> main1.cpp(3) : see declaration of 'C'
main1.cpp(22) : error C2248: 'C::fct2' : cannot access private member declared in class 'C'
1> main1.cpp(6) : see declaration of 'C::fct2'
1> main1.cpp(3) : see declaration of 'C'
1>main1.cpp(24) : error C2248: 'C::fct3' : cannot access private member declared in class 'C'
1> main1.cpp(8) : see declaration of 'C::fct3'
1> main1.cpp(3) : see declaration of 'C'

As expected. But if I do this:

#include <iostream>

class C{
  protected:
    void fct1(){ std::cout << "In C::fct1()" << std::endl; }
    void fct2(){ std::cout << "In C::fct2()" << std::endl; }
  private:
    void fct3(){ std::cout << "In C::fct3()" << std::endl; }
  public:
    void fct_for_everyone(){ std::cout << "In C::fct_for_everyone()" << std::endl; }
};

class R : private C {
  friend class F;
};

class F{
public:
  void CallRFunctions() {
    R someR;
    std::cout << "In F::CallRFunctions()...\n";
    std::cout << "Calling R::fct1()...\n";
    someR.fct1();
    std::cout << "Calling R::fct2()...\n";
    someR.fct2();
    std::cout << "Calling R::fct3()...\n";
    someR.fct3();
    std::cout << "Calling R::fct_for_everyone()...\n";
    someR.fct_for_everyone();
  }
};

int main() {
  F someF;

  someF.CallRFunctions();

  return 0;
}

Somehow F completely bypasses it. And all I get is

main1.cpp(40) : error C2248: 'C::fct3' : cannot access private member declared in class 'C'
main1.cpp(8) : see declaration of 'C::fct3'
main1.cpp(3) : see declaration of 'C'

:confused::confused:

The second part is correct and as C++ rules as I understand them
The first part messages are incomprehensibles. Because the error lines don't agree with the actual source code I suspect you got the code mixed up with some other code explaining the inconsistencies and why it does not follow the access rules

No, it's the correct code, I just took out some commented-out statements to save space. I never even considered that it would mess up the Line numbers to do so...

Here is full code (so numbers match):

#include <iostream>

class C{
  protected:
    void fct1(){ std::cout << "In C::fct1()" << std::endl; }
    void fct2(){ std::cout << "In C::fct2()" << std::endl; }
  private:
    void fct3(){ std::cout << "In C::fct3()" << std::endl; }
  public:
    void fct_for_everyone(){ std::cout << "In C::fct_for_everyone()" << std::endl; }
};

class R : private C {
  //friend class F;
public:
  void CallCFunctions() {
    C someC;
    std::cout << "In R::CallCFunctions()...\n";
    std::cout << "Calling C::fct1()...\n";
    someC.fct1();
    std::cout << "Calling C::fct2()...\n";
    someC.fct2();
    std::cout << "Calling C::fct3()...\n";
    someC.fct3();
    std::cout << "Calling C::fct_for_everyone()...\n";
    someC.fct_for_everyone();
  }
};

/*class F{
public:
  void CallRFunctions() {
    R someR;
    std::cout << "In F::CallRFunctions()...\n";
    std::cout << "Calling R::fct1()...\n";
    someR.fct1();
    std::cout << "Calling R::fct2()...\n";
    someR.fct2();
    std::cout << "Calling R::fct3()...\n";
    someR.fct3();
    std::cout << "Calling R::fct_for_everyone()...\n";
    someR.fct_for_everyone();
  }
};*/

int main() {
  //F someF;
  //someF.CallRFunctions();

  R someR;
  someR.CallCFunctions();

  return 0;
}

As expected, I get:

1>Compiling...
1>main1.cpp
1>c:\users\joshk.lakewoodinc\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(20) : error C2248: 'C::fct1' : cannot access private member declared in class 'C'
1> c:\users\**\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(5) : see declaration of 'C::fct1'
1> c:\users\**\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(3) : see declaration of 'C'
1>c:\users\**\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(22) : error C2248: 'C::fct2' : cannot access private member declared in class 'C'
1> c:\users\**\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(6) : see declaration of 'C::fct2'
1> c:\users\**\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(3) : see declaration of 'C'
1>c:\users\**\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(24) : error C2248: 'C::fct3' : cannot access private member declared in class 'C'
1> c:\users\**\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(8) : see declaration of 'C::fct3'
1> c:\users\**\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(3) : see declaration of 'C'

If I revise the code to this:

#include <iostream>

class C{
  protected:
    void fct1(){ std::cout << "In C::fct1()" << std::endl; }
    void fct2(){ std::cout << "In C::fct2()" << std::endl; }
  private:
    void fct3(){ std::cout << "In C::fct3()" << std::endl; }
  public:
    void fct_for_everyone(){ std::cout << "In C::fct_for_everyone()" << std::endl; }
};

class R : private C {
  friend class F;
public:
  /*void CallCFunctions() {
    C someC;
    std::cout << "In R::CallCFunctions()...\n";
    std::cout << "Calling C::fct1()...\n";
    someC.fct1();
    std::cout << "Calling C::fct2()...\n";
    someC.fct2();
    std::cout << "Calling C::fct3()...\n";
    someC.fct3();
    std::cout << "Calling C::fct_for_everyone()...\n";
    someC.fct_for_everyone();
  }*/
};

class F{
public:
  void CallRFunctions() {
    R someR;
    std::cout << "In F::CallRFunctions()...\n";
    std::cout << "Calling R::fct1()...\n";
    someR.fct1();
    std::cout << "Calling R::fct2()...\n";
    someR.fct2();
    std::cout << "Calling R::fct3()...\n";
    someR.fct3();
    std::cout << "Calling R::fct_for_everyone()...\n";
    someR.fct_for_everyone();
  }
};

int main() {
  F someF;
  someF.CallRFunctions();

  //R someR;
  //someR.CallCFunctions();

  return 0;
}

I only get this:

1>Compiling...
1>main1.cpp
1>c:\users\**\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(40) : error C2248: 'C::fct3' : cannot access private member declared in class 'C'
1> c:\users\**\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(8) : see declaration of 'C::fct3'
1> c:\users\**\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(3) : see declaration of 'C'

It makes sense that F can access the private member(s) of R. I'm not disputing that. What's strange to me is that F can access members of C that R can't. That seems illogical to me.
:confused:

Ok, I have some code that seems to pinpoint the problem:

class C{
  protected:
     void fct(){}
};
class R1:private C{
   void it_works(){
        fct()
   }
};
class R2:private C{
    void it_does_not_works(){
         C c;
         c.fct();
    }
};

The reason ? (Maybe...)
in R1: fct is called via R1 access (protected=allowed because R1 inherits C)
in R2: fct is called via C. C has protected access so it disallows because access is from "outside" not from inherited class

"What's strange to me is that F can access members of C that R can't. That seems illogical to me."
It is illogical but this is not what is happening here. R can access members of C as long as it access them from itself.
In your case you are accessing it from "outside" by instantiating C so you are accessing C::fct instead of R::C::fct

>>It is illogical but this is not what is happening here. R can access members of C as long as it access them from itself.
In your case you are accessing it from "outside" by instantiating C so you are accessing C::fct instead of R::C::fct

Yeah, I realized what I did after I made that last post (cut me some slack, I've been sick for 3 days). I went back and rectified it:

class R : private C {
  //friend class F;
public:
  void CallCFunctions() {
    //C someC;
    std::cout << "In R::CallCFunctions()...\n";
    std::cout << "Calling C::fct1()...\n";
    this->fct1();
    //someC.fct1();
    std::cout << "Calling C::fct2()...\n";
    this->fct2();
    //someC.fct2();
    std::cout << "Calling C::fct3()...\n";
    this->fct3();
    //someC.fct3();
    std::cout << "Calling C::fct_for_everyone()...\n";
    this->fct_for_everyone();
    //someC.fct_for_everyone();
    this->
  }
};

I also did some more reading on the topic. It turns out I had missed a subtle semantic in the description of the inheritance levels when I read about them long ago. Apparently it's just never caused a problem for me until now (probably because my interpretation was more restrictive). Based on my new understanding, it makes sense now.

However, going back to your original posting, you're still not correct.

<snip>

class C{
  protected:
        fct1(){}
        fct2(){}
  private:
        fct3(){}
  public:
        fct_for_everyone(){}
};
 
class R:private C{
  friend F;
}
class F{
};

Here F has access to only fct1 and fct2.
<snip>

If you tweak the code to something like this:

#include <iostream>

class C{
  protected:
    void fct1(){ std::cout << "In C::fct1()" << std::endl; }
    void fct2(){ std::cout << "In C::fct2()" << std::endl; }
  private:
    void fct3(){ std::cout << "In C::fct3()" << std::endl; }
  public:
    void fct_for_everyone(){ std::cout << "In C::fct_for_everyone()" << std::endl; }
};

class R : private C {
  friend class F;
};

class F{
public:
  void CallRFunctions() {
    R someR;
    std::cout << "In F::CallRFunctions()...\n";
    std::cout << "Calling R::fct1()...\n";
    someR.fct1();
    std::cout << "Calling R::fct2()...\n";
    someR.fct2();
    std::cout << "Calling R::fct3()...\n";
    someR.fct3();
    std::cout << "Calling R::fct_for_everyone()...\n";
    someR.fct_for_everyone();
  }
};

int main() {
  F someF;
  someF.CallRFunctions();

  return 0;
}

Look closely at the code, you'll see that it's your original code with some "debugging" (and a main()) added so that you can see what's going on.
If you attempt to compile, you'll see that F also has access to R::C::fct_for_everyone() because the only error the compiler returns is this:

1>Compiling...
1>main1.cpp
1>c:\users\**\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(27) : error C2248: 'C::fct3' : cannot access private member declared in class 'C'
1> c:\users\**\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(8) : see declaration of 'C::fct3'
1> c:\users\**\documents\visual studio 2008\projects\daniweb\daniweb\main1.cpp(3) : see declaration of 'C'
1>Build log was saved at "file://c:\Users\**\Documents\Visual Studio 2008\Projects\daniWeb\DaniWeb\Debug\BuildLog.htm"
1>DaniWeb - 1 error(s), 0 warning(s)
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========

Which means that it can access/find R::C::fct_for_everyone(), but not R::C::fct3() (which it shouldn't be able to). Result, it does not have access to only R::C::fct1() and R::C::fct2().

But the code was to grant selectively access to the private portions (fc1,fct2,fc3) which I did by granting access to fct1, fc2 but not fct3
Of course fct_for_everyone was intended to be unrestrictued

Still the original question remains totally unsolved:

Does anyone has a brilliant (and simple!) way to selectively control access by giving different rights to different friends?

>>But the code was to grant selectively access to the private portions (fc1,fct2,fc3) which I did by granting access to fct1, fc2 but not fct3
Of course fct_for_everyone was intended to be unrestrictued

OK, fine. But that wasn't what you said.
You could probably do something with sub-classes, but that's something I'm still learning myself so I'm not too sure I can help with that possibility.

class Outer{

  class Inner {
    friend class F;
    private:
      void fct1(){ std::cout << "In C::fct1()" << std::endl; }
      void fct2(){ std::cout << "In C::fct2()" << std::endl; }
  };  //end Outer::Inner class

  
  private:
    void fct3(){ std::cout << "In C::fct3()" << std::endl; }
  public:
    void fct_for_everyone(){ std::cout << "In C::fct_for_everyone()" << std::endl; }
};

class F{
};

I'm curious why you want to do this though. Concerns about your design are creeping in to my mind.

Another way is:

struct C{
     protected:
     void fct1(){}
     void fct2(){}
     void fct3(){}
};
struct acces_f1_f2:public C{
  private:
       void fct3; /* no definition */
};
struct acces_f2_f3:public C{
  private:
       void fct1; /* no definition */
};

This way a class can select access rights:
- inherit accesss_f1_f2 for fct1 and fct2 access
- inherit accesss_f2_f3 for fct2 and fct3 access

It works, but this is not simple.
I wonder if there is a suggestion for C++ language improvement such as the following which I would call "scoped friends" with friend only applying to members inside scope

class C{
     { /* scope for friends  - currently not legal */
          friend  class F1;
          void fct1();
     }
     { 
          friend class F1;
          friend class F2;
          void fct2();
      }
     {
          friend class F2;
          void fct3();
      }
};

This way F1 has access to fct1 and fct2, and F2 has access to fct2 and fct3. It is simple and direct.
But perhaps there is an equivalent way already in C++? Does anybody know?

"I'm curious why you want to do this though"
It is too long to explain but it has to do with polymorphic interface and implementation where some derived objects are only allowed to act on selective members.

""I'm curious why you want to do this though"

Actually here is an example of a very useful use.
Say you are writing a vector class.
1) You want to provide public access to checked element access function (checking that element index is withing bounds). All is great.
2) You may also want to provide access to unchecked element access function (with crash risk) to very few and selected other functions. You use "friend". Life is good.
3) You don't want nobody to mess with the internal of your vector: but because you gave friend access in (2) to some function those functions could do that! Life is hard.

Say you are writing a vector class.
1) You want to provide public access to checked element access function (checking that element index is withing bounds). All is great.
2) You may also want to provide access to unchecked element access function (with crash risk) to very few and selected other functions. You use "friend". Life is good.
3) You don't want nobody to mess with the internal of your vector: but because you gave friend access in (2) to some function those functions could do that! Life is hard.

Here is a solution for that problem:

class my_vector {
  private:
    std::vector<int> v;
  public:
    my_vector() : v(5) { };

    // Safe index operators:
    unsigned int size() const { return v.size(); };
    int& operator[](int i) { return v.at(i); };
    int operator[](int i) const { return v.at(i); };

    // Unsafe index operators inside a nested class:
    struct unchecked_access {
      my_vector& parent;
      explicit unchecked_access(my_vector& aParent) : parent(aParent) { };
      unsigned int size() const { return parent.size(); };
      int& operator[](int i) { return parent.v[i]; };
      int operator[](int i) const { return parent.v[i]; };
    };
    struct unchecked_const_access {
      const my_vector& parent;
      explicit unchecked_const_access(const my_vector& aParent) : parent(aParent) { };
      unsigned int size() const { return parent.size(); };
      int operator[](int i) const { return parent.v[i]; };
    };
};

int main() {
  my_vector v;

  v[0] = 42; //uses checked access.
  my_vector::unchecked_access(v)[0] = 69; //uses unchecked access.

  return 0;
};

A nested class has access to all the members, so, a typical means to gain access to a sub-part of the private members of a class is to create a public nested class to provide that functionality. If you want to restrict which classes can use those nested class, just make their functions private and define friends. This solution also causes a certain amount of redundant code (function forwarding, as above). It is also somewhat verbose, but that is a OK because there shouldn't be easy ways to provide access to private members (and the friend relation is often criticized for being too easy to do).

For the more general problem, if you really have sub-parts of your class that are distinguishable enough that you would need different friendship relations for them, then these sub-parts should probably be implemented as separate classes and composition should be used to create the overall class at the end. In other words, try to avoid monolithic classes.

> Does anyone has a brilliant (and simple!) way to selectively control access
> by giving different rights to different friends?

I don't have anything brilliant, but using access helpers to provide selective access is reasonably simple.

class A
{
    void foo() {}
    void bar() {}

    // grant void foo_not_bar( A& ) access to foo, but not to bar
    // grant void bar_not_foo( A& ) access to bar, but not to foo

    public :
        class foo_access_helper
        {
           private: static void foo( A& a ) { a.foo() ; }
           friend void foo_not_bar( A& ) ;
        };
        friend class foo_access_helper ;

        class bar_access_helper
        {
           private: static void bar( A& a ) { a.bar() ; }
           friend void bar_not_foo( A& ) ;
        };
        friend class bar_access_helper ;
};

void foo_not_bar( A& a ) { A::foo_access_helper::foo(a) ; }

void bar_not_foo( A& a ) { A::bar_access_helper::bar(a) ; }

"For the more general problem...."
Good point about the abstraction.

So in the end, there isn't any C++ features for what I want? Are you aware of any discussions for future enhancement (such as the "scoped friends" suggestion above)?

For Vijayan121:
It works but I would not call it simple. Lots of typing for such a simple thing.

>> So in the end, there isn't any C++ features for what I want?

That I know of, there is no specific C++ language feature to allow this.

>> Are you aware of any discussions for future enhancement (such as the "scoped friends" suggestion above)?

I doubt it. The friendship relation is a very frowned upon feature. The expert rarely use it much (I know I don't), and generally say that requiring a friendship relation is an indication of poor design (I know I do). Generally, for standard committee efforts at improving the language, they rarely discuss of ways to make it easier to do the wrong thing, but rather concentrate on easier ways to do the right thing (for examples: rvalue-refs, explicit defaulting/deleting member functions, or the, now abandoned but really awesome, feature of "Concepts").

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.