是否可以在运行时选择可以访问类的私有成员的函数?

时间:2014-02-18 18:16:22

标签: c++ c++11

主题可能令人困惑,但我相信我所追求的概念很容易理解。

我有一个班级,有一些私人数据。我想提供一种在运行时从类外部指定一个可以对该数据进行操作的函数的方法。但是,我不想向公众公开数据。

到目前为止,我有这样的事情:

#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;
}

到目前为止,我不需要更改或选择实现,因此我将该函数声明为静态成员,但现在我喜欢上面的示例,我可以提供mix_privates的几种不同实现。此外,我有许多类似于Base的对象,可以很容易地为它们概括mix_privates,例如通过模板。

理想情况下,我希望能够定义几个mix_privates实现。例如:

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;
}

然后在main中为一些通用名称指定一个具体的实现,例如:

std::function<void(Base&, Base&)> mix_privates = mix_privates_avg<Base>

然后在整个程序的其余部分使用通用名称mix_privates(test1, test2)的混音器。

如果mix_privates仅使用公共成员和属性,则没有问题,我完成了它。但我希望能够搞乱私人数据。除了这个功能之外,将它公开给公众也没有意义,所以我想避免它。

我在考虑使用友谊,但它不是可继承的,这是一个缺点,而且不可转让,所以我想我不能指定一个像代理一样的朋友功能。

有没有办法在c ++ 11中实现这个或类似的东西?

3 个答案:

答案 0 :(得分:3)

提供定义 protected getter / setter方法的朋友怎么样?这样只有朋友的派生类才能访问内部。 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)); }
};

答案 1 :(得分:3)

与其他建议相反,我会考虑将mix_privates作为一个模板,该模板采用可以实际混合的函数:

template <typename Functor>
void Base::mix_privates(Base& b1, Base& b2, Functor f) {
   b1.priv = b2.priv = f(b1,b2);
}

然后你可以使用它:

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

答案 2 :(得分:1)

您可以创建一个实现函数Mixer的{​​{1}}类,并在mix(Base& b1, Base& b2)中声明它的实例。然后子类Base来实现各种混合方式。将所需Mixer子类的实例分配给Mixer中声明的实例,然后实现Base以调用实例的mix_privates

例如:

mix

问题是(正如所指出的),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); ... } 及其子类无法访问Mixer的私有成员。因此,您可以使Base成为朋友,并实现子类可以使用的方法来访问base的私有成员。例如:

Mixer