luk32
luk32

Reputation: 16080

Is it possible to chose at runtime function that can access private members of a class?

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

Answers (3)

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

Trenin
Trenin

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

JoshG79
JoshG79

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

Related Questions