2014-02-18 61 views
1

這個話題可能會令人困惑,但我相信我所追求的理念很容易理解。是否可以在運行時選擇可以訪問類的私有成員的函數?

我有一個班,有一些私人數據。我想提供一種在運行期間從一個可以操作這些數據的類的外部指定一個函數的方法。但是,我不想公開這些數據給公衆。

到目前爲止,我有這樣的事情:

#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中實現這個或類似的東西?

+0

有什麼可以排除setter?沿着'void Base :: set(double a){priv = a; }'。這是對你太多的闡述嗎? – stefan

+0

封裝是一個編譯時的功能。在運行時沒有公共/私有/受保護的概念。爲什麼你就不能使用'get_private()'和'set_private()'訪問數據? –

+0

所以你不想讓它容易改變的私人數據,但你希望能夠寫出任何數量的不相關的功能,可以改變私有數據? – aschepler

回答

1

您可以創建一個Mixer類,該類實現函數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私有成員。所以,你可以讓Mixer成爲朋友,並實現方法,然後子類可以使用方法來訪問base的私有成員。例如:

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

這不會編譯,怎麼做'MixAverage'訪問'Base'的私有成員? – imreal

+0

你是對的,但你可以讓它成爲朋友。 – Trenin

+0

我覺得還可以跳過'Base'靜,只是去'攪拌機&攪拌機= MixAverage(); mixer.mix(b1,b2);'in'main'。我是hella累了,但它認爲它應該工作。那麼這是一個好主意。 – luk32

3

關於提供朋友該定義保護 getter/setter方法是什麼?這樣,只有朋友的派生類可以訪問內部。例如。:

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)); } 
}; 
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 
相關問題