I have class, say Rectangle
that has a private method Rectangle::paint
. I want to let two other classes access this method, and only those two. So, I thought of this:
template <class T, class Q>
class Rectangle {
void paint();
friend T;
friend Q;
};
Problem is, when I want to instantiate a Rectangle
object in T
, it means T
needs to know about Q
, either by including a header or by using a forward declaration, both of which I would like to avoid. Also, the other way around regarding Q
not knowing about T
. Is there a way to do this?
Edit: To clarify a bit, I want to instantiate Rectangle
in Foo
, but have it mean Rectangle<Foo, Bar>
so that Bar could access private members from elsewhere. I don't want Foo
to know about Bar
or vice versa.
Thanks
CodePudding user response:
If Rectangle
is a template and parametrized on Q
and T
, then Q
and T
are part of the type. You cannot use Rectangle<Q,T>
without "knowing" about Q
or T
.
How about this:
template <size_t> struct rectangle;
template <size_t tag>
struct rectangle_modifier {
void paint(rectangle<tag>&);
};
template <size_t tag>
struct rectangle {
friend rectangle_modifier<tag>;
private:
void paint() {}
};
template <size_t tag>
void rectangle_modifier<tag>::paint(rectangle<tag>& r) {r.paint(); }
struct foo : rectangle_modifier<1> {};
struct bar : rectangle_modifier<1> {};
int main () {
rectangle<1> r;
foo{}.paint(r);
bar{}.paint(r);
}
foo
and bar
need not know anything about each other. They both can paint
a rectangle<1>
. The tag
is because you said you want to have different rectangles that each let two different classes access their paint
.
Note that this is rather intrusive (foo
and bar
must inherit), not sure if this is a problem.
Its also not safe in the sense that anybody can write another class that inherits from rectangle_modifier<1>
to access rectangle<1>::paint
. However, thats not really what private
is for. private
is to restrict accidential access and to make clear that one should not access it. It is not to prevent by all means that it can be accessed. If someone wants to hack it, they will find a way.
Actually I would simply make rectangle::paint
public and call it a day. Encapsulation is to make sure invariants don't break. Painting a rectangle that can be painted does not break an invariant.