Reputation: 16080
The topic might be a it confusing but I believe the concept I am after is pretty easy to grasp.
I have a class, that has some private data. I would like to provide a way to specify a function from the outside of a class that can operate on this data, during the run time. However, I would not like to expose the data to the public.
So far I had something like this:
#include <iostream>
using namespace std;
class Base{
double priv = 0;
public:
Base(double initial) : priv(initial) {};
double get_private(){ return priv; };
static void mix_privates(Base& b1, Base& b2);
};
void Base::mix_privates(Base& b1, Base& b2){
b1.priv = b2.priv = (b1.priv+b2.priv)/2;
}
//void Base::mix_privates(Base& b1, Base& b2){
// b1.priv = b2.priv = max(b1.priv, b2.priv);
//}
int main() {
Base test1(5), test2(10);
Base::mix_privates( test1, test2 );
cout << test1.get_private() << '\n';
cout << test2.get_private() << '\n';
return 0;
}
Up to this point I did not need to change or choose the implementation so I declared the function as a static member, but now I like in the example above I can provide several different implementations of mix_privates
. Moreover I have many objects similar to Base
and can easily generalize mix_privates
for them, for example via template.
Ideally I would like to be able to do is to define few mix_privates
implementations. For example like this:
template<typename BaseLike>
void mix_privates_max(BaseLike& b1, BaseLike& b2){
b1.priv = b2.priv = max(b1.priv, b2.priv);
}
template<typename BaseLike>
void mix_privates_avg(BaseLike& b1, BaseLike& b2){
b1.priv = b2.priv = (b1.priv + b2.priv)/2;
}
And then in main
assign a concrete implementation to some general name, e.g:
std::function<void(Base&, Base&)> mix_privates = mix_privates_avg<Base>
and then use mixer through general name mix_privates(test1, test2)
through out rest of the program.
There is no problem if mix_privates
uses only public members and attributes, and I got it done. But I would like to be able mess with private data. There is also no point in exposing it to public except for this functionality, so I would like to avoid it.
I was thinking about using friendship, but it is not inheritable, which is a drawback, and not transferable, so I think I cannot specify a friend function that would act like a proxy.
Is there a way to implement this or something similar in c++11?
Upvotes: 1
Views: 186
Reputation: 208436
Contrary to the other suggestions, I would consider making mix_privates
a template that takes a function that will do the actual mix:
template <typename Functor>
void Base::mix_privates(Base& b1, Base& b2, Functor f) {
b1.priv = b2.priv = f(b1,b2);
}
Then you can use it:
Base b1(..), b2(..);
Base::mix_privates(b1,b2,
[](double x, double y) { return (x+y)/2; }); // average
Base::mix_privates(b1,b2,
&std::max<double>); // max
Upvotes: 3
Reputation: 2063
You could create a Mixer
class which implements a function mix(Base& b1, Base& b2)
, and declare an instance of it in Base
. Then subclass Mixer
to implement the various ways to mix. Assign an instance of your desired Mixer
subclass to the instance declared in Base
, and then implement mix_privates
to call mix
of the instance.
For example:
class Mixer;
class Base{
double priv = 0;
public:
...
static Mixer* mixer;
static void mix_privates(Base& b1, Base& b2) {
mixer->mix(b1, b2);
};
};
class Mixer {
public:
void mix(Base& b1, Base&b2) = 0;
};
class MixAverage : public Mixer {
public:
void mix(Base& b1, Base&b2) {
b1.priv = b2.priv = (b1.priv+b2.priv)/2;
};
}
main {
...
Base b1, b2;
Base::mixer = new MixAverage();
...
Base::mix_privates(b1, b2);
...
}
The problems with this is (as pointed out), the Mixer
and its subclasses cannot access the private members of Base
. So, you could make Mixer
a friend, and implement methods that can then be used by the subclass to get access to the private member of base. For example:
class Base{
double priv = 0;
public:
...
static Mixer* mixer;
static void mix_privates(Base& b1, Base& b2) {
mixer->mix(b1, b2);
};
friend class Mixer;
};
class Mixer {
public:
void mix(Base& b1, Base&b2) = 0;
int& priv(Base& b) {
return b.priv;
};
};
class MixAverage : public Mixer {
public:
void mix(Base& b1, Base&b2) {
priv(b1) = priv(b2) = (priv(b1)+priv(b2))/2;
};
}
Upvotes: 1
Reputation: 1687
What about providing a friend class that defines protected getter/setter methods? That way only derived classes of the friend can access the internals. E.g.:
class Base {
friend class Access;
...
private: double priv;
};
class Access {
protected:
double get_private(Base &b) { return b.priv; }
void set_private(Base &b, double priv) { b.priv = priv; }
public:
virtual void mix_privates(Base &b1, Base &b2) = 0;
};
class AccessMax : public Access {
void mix_privates(Base &b1, Base &b2) { set_private(b1, max(get_private(b1), get_private(b2)); }
};
Upvotes: 3