I have a data structure, and two classes accessing it:
class Foo {
public:
void set(double foo);
double get();
};
class FooWriter {
Foo bar;
void setFoo() { bar.set(42); }
};
class FooReader {
Foo *baz;
double getFoo() { return baz->get(); }
};
I would like to restrict FooReader to read Foo, and allow setting only for FooWriter. Private set function and friend class would be an option but unfortunately I have a lot of subclasses of FooWriter, and since friendship can not be inherited, I would not like to list them all as friends. Bypassing encapsulation with protected method in friend FooWriter superclass is an other option:
class Foo {
void set(double foo);
public:
double get();
friend class FooWriter;
};
class FooWriter {
Foo bar;
protected:
void setFooBackdoor(double value) { bar.set(value); }
};
class subFooWriter {
void setFoo() { setFooBackdoor(42); }
};
but some would consider this as bad design. I've also read here that if you need friendship inheritence, there is a flaw in your design, so I'm curious, what would be the proper solution for this problem.
Related
pimpl.h
#include <memory>
class MyClassImpl;
class MyClass {
void Foo();
struct MyStruct {
int a;
int b;
} variable_struct;
private:
std::unique_ptr<MyClassImpl> m_pImpl;
};
pimpl.cpp
class MyClassImpl
{
public:
void DoStuff() { /*...*/ }
struct MyStructImpl {
int a;
int b;
} variable_struct_impl;
};
// MyClass (External/User interface)
MyClass::MyClass () : m_pImpl(new MyClassImpl()) { }
MyClass::~MyClass () = default;
void MyClass::Foo() {
m_pImpl->DoStuff();
}
How/What's the best practice to share a public member of the implementation to the Pimpl class (end user)?
What if they have a different name like in my example with struct MyStruct and struct MyStructImpl (variable_struct / variable_struct_impl)?
For methods, that's quite clear, we need to make the forward method anyway. (Foo() forwarded to DoStuff() in the example)
How to give access to public members with Pimpl?
You don't. The point of PIMPL is to hide all members of the Private IMPLementation, and having public access to them is entirely contrary to that point.
If you want pubic access, then don't put the member in a PIMPL.
The following code doesn't work, as you can't static_cast from private base class.
Replacing the cast with a C-style cast works (although I originally thought this would invoke undefined behaviour apparently it does not, see this answer), but is rather ugly as it also allows you to bypass const-checking, etc. The other approach would be to make CRTPBase a friend, but that would expose all of Derived's private members.
Is there another way of writing this without using a C-style cast and without making CRTPBase a friend?
template<typename T>
struct CRTPBase {
void callBase() {
T * derived = static_cast<T*>(this);
derived->publicMethod();
}
};
struct Derived : private CRTPBase<Derived> {
void callParent() { this->callBase(); }
void publicMethod() {}
};
int main() {
Derived d;
d.callParent();
return 0;
}
I think the best solution is to avoid private inheritance and instead opt for data hiding.
Marking the member function protected will prevent access from everywhere except derived classes. A further bonus public inheritance is used instead.
template<typename T>
class CRTPBase {
protected:
void callBase() {
T * derived = static_cast<T*>(this);
derived->publicMethod();
}
};
struct Derived : public CRTPBase<Derived> {
void callParent() { this->callBase(); }
void publicMethod() {}
};
int main() {
Derived d;
d.callParent();
d.callBase() // <- illegal
return 0;
}
Not an ideal solution, but you can restrict the friendship to a unique method as follow:
template<typename T>
struct CRTPBase {
friend T; // So T can see asDerived.
void callBase() { asDerived()->publicMethod(); }
private:
T* asDerived() { return static_cast<T*>(this); }
};
struct Derived : private CRTPBase<Derived> {
friend Derived* CRTPBase<Derived>::asDerived();
void callParent() { this->callBase(); }
void publicMethod() {}
};
Let's have a class A which has an inner class A::Impl. A class AllowedToAccess should be able to get A::Impl& from class A, no other class should be able to do that or even know that class A::Impl exists.
class A_1
{
public:
class Impl;
Impl& impl();
const Impl& impl() const;
private:
std::unique_ptr<Impl> m_impl;
};
class A_2
{
private:
friend class AllowedToAccess;
class Impl;
std::unique_ptr<Impl> m_impl;
};
class A_3
{
private:
friend class AllowedToAccess;
class Impl;
class ImplContainer
{
friend class A_3;
std::unique_ptr<Impl> impl;
} m_implContainer;
Impl& impl(); // return *m_implContainer.impl;
const Impl& impl() const; // return *m_implContainer.impl;
};
Here is some code to illustrate my ideas.
A_1
Pros: m_impl is secured.
Cons: classes not supposed to know about A::Impl will know about it (although they don't know what A::Impl really is about).
A_2
Pros: classes not supposed to know about A::Impl will not know about it.
Cons: m_impl is not secured (AllowedToAccess might just set it to nullptr).
A_3
Pros: classes not supposed to know about A::Impl will not know about it and m_impl is secured.
Cons: Boilerplate code for ImplContainer.
Any better ideas?
EDIT: Came up with a solution like this.
template <typename T>
class Accessor
{
private:
friend class AllowedToAccess;
typedef typename T::Impl impl_t;
static typename T::Impl& impl(T& t)
{
return *t.m_impl;
}
static const typename T::Impl& impl(const T& t)
{
return *t.m_impl;
}
};
class A
{
private:
friend class Accessor<A>;
class Impl;
std::unique_ptr<Impl> m_impl;
};
class A::Impl
{
public:
void f() const
{
}
};
class AllowedToAccess
{
public:
AllowedToAccess()
{
const A a;
const Accessor<A>::impl_t& impl = Accessor<A>::impl(a);
impl.f();
}
};
There is an implementation layer of code, and all those classes will be added as friends to Accessor.
And to further hide things the accessor would only be forward declared as template <typename T> class Accessor; in public code. And defined in private code.
If it is possible to move all logic that works with m_impl itself to a base class, you can make m_impl inaccessible to a derived class, but allow it to get a refernce to Impl, and then make Access class a friend of a derived class:
class Base {
protected:
class Impl;
Impl& impl();
private:
std::unique_ptr<Impl> m_impl;
};
class Base::Impl {
public:
Impl() {}
};
Base::Impl& Base::impl() { return *m_impl; }
class Derived : private Base {
public:
friend class Access;
Derived() {
auto& ptr = impl(); // ok
auto& ptr1 = m_impl; // error
}
};
class Access {
public:
Access(Derived& d) {
auto& ptr = d.impl(); // ok
auto& ptr1 = d.m_impl; // error
}
};
I don't know if its a better idea, but you could provide your own implementation of AllowedToAccess, that would safely expose needed interface. I call it Accessor.
class Base{
double priv = 0;
public:
friend class Accessor;
};
class Accessor {
public:
int& priv(Base& b) { return b.priv; };
};
Now classes can access exposed privates through Accessor. The semantics change a bit though because you use it like accessor.priv(b) = something but you have full control over the exposed interface. I think Accessor in this variation could have all static methods since the accessed object is passed always anyways. So the semantics would be Accessor::priv(b).
I guess it is a variation of your A_3 example, with code moved into the friend class. But it does not pollute A_ class.
Another option would be to provide your own Accessor class in form of a simple wrapper.
class Accessor {
public:
Accessor(Base b) _b(b);
int priv() { return _b.priv; };
int priv(int val) { _b.priv = val; };
int& priv_r() { return _b.priv; };
private:
Base& _b;
};
The interface here is also fully customizable, and you can access features like:
Base b;
Accessor interface(b);
interface.priv(42);
You can also make it absolutely safe disallowing to derive from Accessor (there are tricks for that), so no-one can derive and screw up your objects via an evil implementation of the Accessor. I think it would be a little bit paranoid though.
How about this:
class A_4
{
public:
class Impl;
Impl& impl();
const Impl& impl() const;
private:
std::unique_ptr<Impl> m_impl;
};
class A_4::Impl
{
private:
friend class A_4;
friend class AllowedToAccess;
Impl();
~Impl();
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
// All members private!
};
It doesn't matter that code can call impl() or write A_4::Impl if there's nothing useful they can actually do with it.
I have a set of classes that are replies from the network. Some classes uses function foo, while others use bar. I was thinking of just have a class that sets the variable inside foo and bar. Then inherit those classes which just only have function foo and bar functions without constantly defining the functions in those classes. For example.
class Foo {
public:
Foo():
foo_(std::string()) {}
virtual ~Foo(){}
const std::string& foo() const { return foo_; }
private:
std::string foo_;
};
class FooReply:
public Foo {
public:
FooReply(){}
explicit FooReply(const std::string& reply):
setFoo(reply) {
}
FooReply(const FooReply& other):
Foo(other) {
}
~FooReply(){}
FooReply& operator=(const FooReply& other) {
Foo::operator=(other);
return *this;
}
};
Would it be better to do this, or should I just make them an interface and just reimplement the foo() function? Since I'm only inheriting one function.
I have a template class for which I need to access a protected member function of the template parameter, like this:
class Foo
{
protected:
void foo() {}
};
template<typename T>
class Bar
{
public:
static void bar(T& self){self.foo();}
};
...
Foo f;
Bar<Foo>::bar(f);
My problem is getting access to the protected method. I tried putting a friend class T into Bar, but that doesn't seem to be allowed in c++ (edit: and wouldn't solve my problem anyways, so it seemd). I tried letting Bar inherit from T (template<typename T> class Bar: public T (could have used private inheritance, but the public interface of Bar is not terribly important, since the class itself is internal only)), but that didn't allow for access of foo() either. So how do I get access to the foo() method?
Edit:
Foo should not need to know Bar<Foo>, since there are quite a lot Bar classes. I can however make other changes to Foo (without changing the public interface of course).
OK, this is a "rot in hell" hack. You can abuse the fact that you can form pointers-to-members pointing to protected base members from a derived class.
class Foo
{
protected:
void foo() {}
};
// Helper template to bypass protected access control
// for a member function called foo, taking no parameters
// and returning void.
template<typename T>
struct Unprotect : public T
{
typedef void (T::*FooPtr)();
static FooPtr GetFooPtr()
{
return &Unprotect::foo;
}
};
template<typename T>
class Bar
{
public:
static void bar(T& self){(self.*Unprotect<Foo>::GetFooPtr())();}
};
int main()
{
Foo f;
Bar<Foo>::bar(f);
}
You did your friend declaration in the wrong direction. If Bar says Foo is it's friend, that means Foo gets access to Bar's private data. For Bar to get access to Foo's private data, Foo has to say Bar is its friend.
template<typename T>
class Bar
{
public:
static void bar(T& self){self.foo();}
};
class Foo
{
protected:
void foo() {}
friend class Bar<Foo>;
};
void main()
{
Foo f;
Bar<Foo>::bar(f);
}
If you want to access a protected member a derived class of this, you can do it with the using keyword:
class A
{
protected:
void i_am_protected () {}
};
template <class T>
class B : public T
{
using T::i_am_protected;
void call_me ()
{
i_am_protected(); // OK.
this->i_am_protected(); // This compiles without the keyword.
}
};
If you need B to access a protected member of A when an object is passed to B, you need to declare B as a friend of A:
class A
{
template <class T>
friend
class B;
protected:
void i_am_protected () {}
};
template <class T>
class B : public T
{
void call_me (T& obj)
{
obj.i_am_protected(); // OK.
}
};