I am working on some code, where I encountered a situation similar to this one:
struct Bar;
struct Foo{
friend struct Bar;
private:
Foo(){}
void f(){}
void g(){}
};
struct Bar {
Foo* f;
Bar() { f = new Foo();}
~Bar() { delete f;}
};
int main(){
Bar b;
}
I would prefer to have Bar not as friend of Foo, because besides Foos constructor Bar does not need access to any of Foos private methods (and thus should not have access). Is there a way to allow only Bar to create Foos without making them friends?
PS: realized that the question might not be 100% clear. I don't mind if it is via friends or not, just the fact that all Bar has access to all private methods is disturbing me (which is usually the case with friends) and that is what I want to avoid. Fortunately none of the answers given so far had a problem with that lousy formulation.
This is precisely what the attorney-client idiom is for:
struct Bar;
struct Foo {
friend struct FooAttorney;
private:
Foo(){}
void f(){}
void g(){}
};
class FooAttorney {
static Foo* makeFoo() { return new Foo; }
friend struct Bar;
};
struct Bar {
Foo* f;
Bar() { f = FooAttorney::makeFoo();}
~Bar() { delete f;}
};
int main(){
Bar b;
}
In a code imitates life fashion, the class declares an attorney that will mediate the secrets it's willing to share with the selected parties.
If you do not want to introduce another class, you can shrink the circle of friendship and make Bar's constructor Foo's friend. It requires Bar's definition to be available to Foo, and it still gives Bar's constructor unrestricted access to Foo's private implementation:
struct Foo;
struct Bar {
Foo* f;
Bar();
~Bar();
};
struct Foo{
friend Bar::Bar();
private:
Foo(){}
void f(){}
void g(){}
};
Bar::Bar() : f(new Foo()) {
}
Bar::~Bar() {
delete f;
}
This does not achieve exactly what you want, but it makes friendship a lot more targeted.
One way that occurred to me was to have an internal class that makes Bar its friend so only Bar can create it and that internal class can be used as an additional parameter to Foo constructor so only the class's friends can invoke it.
class Foo
{
public:
// only friends of the special key can invoke the constructor
// or any member function that includes it as a dummy parameter
class special_key {friend class Bar; special_key(){}};
// making special_key a dummy parameter makes sure only friends of
// the special key can invoke the function
Foo(special_key) {}
void f(){}
void g(){}
};
class Bar
{
public:
// only Bar functions can create the special key
Bar() { f = std::make_unique<Foo>(Foo::special_key()); }
private:
std::unique_ptr<Foo> f;
};
As well as restricting access to specific functions this technique also allows the use of smart pointer make functions which direct friendship does not.
Related
Is there a way to ensure that only class Fabric can construct the class Foo and all of its sub-classes, without having to declare a private constructor and friend class Fabric in each sub-class?
struct Foo {
friend class Fabric;
protected:
Foo() = default;
};
struct FooConcrete1 : Foo {
friend class Fabric;
protected:
Foo() = default;
};
Since friendship is not inherited, both manual actions when declaring each sub-class seem to be needed, which is error-prone.
One option is to declare a tag structure which is only constructible by Fabric and pass this object to the constructor of Foo. If you forget to add the constructor to derived classes you will get an error that Foo isn't default constructible.
struct FooTag
{
friend struct Fabric;
private:
FooTag();
};
struct Foo {
Foo(FooTag tag) {}
};
struct FooConcrete1 : Foo {
using Foo::Foo;
};
struct Fabric
{
void test()
{
FooConcrete1 f = FooConcrete1(FooTag());
}
};
int main()
{
FooConcrete1 f; // can't construct as we can't construct FooTag
return 0;
}
I am unsure about the order of declaration in my class. My compiler says error: "Foo" was not declared in this scope. If I change the order of public and private parts of the class, I end up with the same error. Also, if I want to use the getFoo(), and I am including my header file, the struct Foo type is not visible because it's private. But if I put it in public scope again, then public would have to come before private because otherwise the declaration of myFoo of type Foo can't happen since Foo was not decalred yet.
I am confused here... thanks for your help!
/*MyClass.h*/
class MyClass
{
private:
struct Foo{
int bar;
};
Foo myFoo;
public:
Foo getFoo(){ return myFoo;}
};
It has nothing to do with public or private. Your inner type has to be defined before it is used:
struct Foo
{
Bar bar() { return Bar(); } // ERROR
struct Bar {};
};
struct Foo
{
struct Bar {};
Bar bar() { return Bar(); } // OK
};
Note: there has been some confusion concerning the accessibility of a private type. THe type is accessible outside of its class, it just cannot be named. So, this code that accesses the private type is completely legal:
class Foo
{
struct Bar {
void do_stuff() const {}
};
public:
Bar bar() { return Bar(); } // OK
};
int main()
{
Foo f;
f.bar().do_stuff(); // use temporary Bar object
// In C++11, you can even make a named instance
auto b = f.bar(); // instantiate a Bar object called b
b.do_stuff(); // use it
}
Your struct Foo should be public otherwise getFoo getter will not work as Foo is accessible only inside your class
I have some troubles understanding how to manage the access rights of virtual methods. I made two small code samples, but I can't understand how things work.
Code Sample 1
The first code contains 3 classes: a mother class Foo and two derived classes. The class Baz looks a little bit like a Composite. There's a virtual method, but it's protected.
class Foo
{
protected:
virtual void doIt() = 0;
};
class Bar : public Foo
{
protected:
void doIt()
{}
};
class Baz : public Foo
{
protected:
void doIt()
{
M_foo->doIt(); // Error here
}
private:
Foo* M_foo;
};
When trying to compile (Visual C++ 2010) this, I get an error: I can't call doIt from a pointer to Foo in the derived class. So, my understanding was "I can't call this method because it could actually call another one (e.g. the one of Bar) to which I have no right".
Code Sample 2
I decided to change a bit the design of the code and design a function instead of the virtual method. However, to access a protected method, I need to add friendship with my function.
class Foo
{
friend void doItPlease( Foo* foo);
protected:
virtual Foo* getChild() = 0;
};
class Bar : public Foo
{
protected:
Foo* getChild()
{ return 0;}
};
class Baz : public Foo
{
protected:
Foo* getChild()
{
return M_foo;
}
private:
Foo* M_foo;
};
void doItPlease( Foo* foo)
{
Foo* myFoo( foo->getChild() );
};
This code compiles fine. The problem is that I can't understand why: I have declared only the base class as friend, not the children classes and friendship is not inherited. But now, when I call getChild from the function, it is like I would call a method to which I have no right (the one in Baz e.g.).
Could someone explain me how are the rights related to virtual methods managed?
Those are the rules for protected. They allow access to the base class subobject, but not for any unrelated instances like yours.
If you google for protected, you will find advice to avoid it in the first place, use private and public only, the intermediate is quite rarely good.
The point is that you define privateness from base class' perspective. If some action is allowed from the outside, it's irrelevant that the unknown party is freestanding or happens to be a subclass. The only relevant attribute is it's being known to be trusted or not.
If the particular derived class is defined along with base, feel free to make it friend, just keep maintaining the rules.
class Foo
{
public:
friend class Baz;
protected:
virtual void doIt() = 0;
};
class Baz : public Foo
{
public:
Baz(Foo* foo)
: M_foo(foo)
{
}
protected:
void doIt()
{
M_foo->doIt();
}
private:
Foo* M_foo;
};
This could not work beacause Foo::doIt is an undifined virtual method method
class Baz : public Foo
{
protected:
void doIt()
{
Foo::doIt();
}
};
But if you have something like this it's should work fine
class Baz : public Foo
{
Baz()
{
M_foo = new Bar();
}
protected:
void doIt()
{
M_foo->doIt();
}
private:
Foo* M_foo;
};
How to limit access to class function from main function?
Here my code.
class Bar
{
public: void doSomething(){}
};
class Foo
{
public: Bar bar;
//Only this scope that bar object was declared(In this case only Foo class)
//Can access doSomething() by bar object.
};
int main()
{
Foo foo;
foo.bar.doSomething(); //doSomething() should be limited(can't access)
return 0;
}
PS.Sorry for my poor English.
Edit:
I didn't delete old code but I expand with new code.
I think this case can't use friend class. Because I plan to use for every class. Thanks
class Bar
{
public:
void A() {} //Can access in scope that object of Bar was declared only
void B() {}
void C() {}
};
class Foo
{
public:
Bar bar;
//Only this scope that bar object was declared(In this case is a Foo class)
//Foo class can access A function by bar object
//main function need to access bar object with B, C function
//but main function don't need to access A function
void CallA()
{
bar.A(); //Correct
}
};
int main()
{
Foo foo;
foo.bar.A(); //Incorrect: A function should be limited(can't access)
foo.bar.B(); //Correct
foo.bar.C(); //Correct
foo.CallA(); //Correct
return 0;
}
Make Foo a friend of Bar
class Bar
{
friend class Foo;
private:
void doSomething(){}
};
And also avoid making member variables public. Use setters/getters instead
You can define Foo as a friend class of Bar and make doSomething() private.
Making Bar bar private inside Foo would do the trick, would it not?
Then only the class Foo could use bar.
Suppose we have two classes:
class Base
{
private:
int x;
public:
void f();
};
class Foo
{
// some variables and methods
};
Now everyone can call Base::f(), but I want only Foo to be able to do so.
In order to achieve this effect, we can make Base::f() private and declare Foo as a friend:
class Base
{
private:
int x;
void f();
friend Foo;
};
The problem with this approach is that Foo has the access to both Base::f() and Base::x (and even to any other private members of Base). But I want Foo to have access only to Base::f().
Is there a way for a class (or a function) to grant an access only to certain private members of another class? Or maybe anyone could suggest a better approach to my problem?
EDIT:
I'll try to specify the access restriction I need. Firstly, Base is an interface in a library (it's an abstract class, in fact). The user uses only the classes derived from Base. Base::f() is called only by Foo which is another class in the library. Hiding Base::f() from the user is important, because only Foo knows when to call it. At the same time, Foo shouldn't mess up the other members of Base.
Very hacky, but this will allow very fine grained access.
class Base
{
private:
int x;
void f();
friend class Base_f_Accessor;
};
class Base_f_Accessor
{
private:
static void f(Base & b) { b.f(); }
friend class Foo;
}
class Foo
{
// some variables and methods
};
You can create another class that contains the data for Base like this:
class BaseData {
protected:
int x;
};
class Base : public BaseData {
friend class Foo;
void f ();
};
Now, Foo can access f as a method of Base like you wanted, but not x. Friendship is not commutative. By using protected, x appears private to everyone except those that derived directly from BaseData.
A better approach might be to use multiple inheritance to define Base, and provide Foo access only to those classes you want from which Base derives.
class With_f {
friend class Foo;
protected:
virtual void f () = 0;
};
class With_g {
protected:
virtual void g () = 0;
};
class Base : public With_f, public With_g {
int x;
void f () {}
void g () {}
};
Here, Foo would have to have a With_f pointer to Base, but it could then access the f method. Foo could not access g.
There's no easy, non-hackish way to achieve that. C++ simply doesn't have such access control granularity. You can play with some inheritance, but increased complexity outweighs any advantages this access restriction might have. Also, this approach doesn't scale - you can grant increased permissions only to one friend class.
Maybe a bit cumbersome, but you could make nested classes where the nesting class is friend, then you can add friends per nested class. This gives some level of granularity:
#include <iostream>
class Nesting
{
friend class Foo;
class Nested1
{
friend class Nesting;
public:
Nested1() : i(3) { }
private:
int i;
} n1;
class Nested2
{
friend class Nesting;
friend class Foo;
public:
Nested2() : j(5) { }
private:
int j;
} n2;
int f() { return n1.i; }
};
class Foo
{
public:
Foo(Nesting& n1) : n(n1) { }
int getJ() { return n.n2.j + n.f(); }
private:
Nesting& n;
};
int main()
{
Nesting n;
Foo foo(n);
std::cout << foo.getJ() << "\n";
}