2010-11-19 20 views
17

In C#/.NET si può fare qualcosa di simile:Proprietà di tipo C# in C++ nativo?

someThing.text = "blah"; 
String blah = someThing.text; 

Tuttavia, il codice di cui sopra non interagiscono con lo String il testo del qualcosa direttamente, utilizza un get e set di proprietà. Allo stesso modo, è possibile utilizzare proprietà di sola lettura.

C'è un modo per fare qualcosa di simile nel nativo C++? (non C++ .NET)

+0

Io non sono un esperto, ma perché non lasciare 'someThing.text' essere un membro del pubblico, se avete intenzione di trattarlo come uno comunque ? – flies

+2

L'esposizione di membri (anche se di sola lettura) tramite getter e setter non è buona. Stai esponendo la rappresentazione interna del tuo oggetto al mondo. Anche se questo è leggermente protetto usando metodi (nascosti dietro lo zucchero sintattico delle proprietà) fornisce un'API pubblica che deve essere mantenuta. La domanda è: perché stai cercando di esporre i tuoi membri? L'oggetto dovrebbe utilizzare la rappresentazione interna per eseguire attività che non sono esposte ad altre persone per eseguire attività. Anziché esporre l'implementazione, esporre un metodo di azione che utilizza la rappresentazione. –

+0

Mi interrogo sull'utilità di pagare un costo di efficienza per oscurare il codice. –

risposta

15

Nelle proprietà .NET sono zucchero sintattico per le funzioni reali get e set che vengono emesse dietro le quinte (in realtà sono più di zucchero sintattico perché le proprietà vengono emesse nell'IL risultante e potrebbero essere usato con Reflection). Quindi in C++ avresti bisogno di scrivere esplicitamente quelle funzioni in quanto non esiste tale nozione come proprietà.

+0

Ma come fa a sapere se il l'utente vuole ottenere o impostare? È necessario utilizzare il sovraccarico dell'operatore? – jmasterx

+1

Quando si trova sul lato sinistro dell'operatore di assegnazione ('=') che si sta impostando, quando si trova sulla destra si sta ottenendo e il compilatore è abbastanza intelligente da capirlo. –

+0

Scrivendo due funzioni su quello restituirà un riferimento, e quello che restituirà un riferimento const è molto utile, il compilatore capirà quando chiamare quale. Ma questo permetterà di effettuare queste chiamate in qualsiasi posto (all'interno delle funzioni const). – Jbad26

0

No, non c'è. Si potrebbe solo creare funzioni getter e setter:

someThing.setText("blah"); 
std::string blah = someThing.getText(); 
2

una proprietà in .NET è associato ad un get e/o una funzione set membro, quindi è davvero solo zucchero sintattico. Il più vicino si può ottenere con C++ è quello di utilizzare un sovraccarico per dare il getter e setter lo stesso nome:

const std::string &test() const { return text_; } 
void test(const std::string &value) { text_ = value; } 

Ovviamente, sarà comunque necessario fornire parentesi per la chiamata:

someThing.text("blah"); 
String blah = someThing.text(); 
15

avverto tu: non è nativo C++; è specifico per Microsoft solo. Ma è possibile utilizzare declspec(property):

struct S { 
    int i; 
    void putprop(int j) { 
     i = j; 
    } 

    int getprop() { 
     return i; 
    } 

    __declspec(property(get = getprop, put = putprop)) int the_prop; 
}; 

int main() { 
    S s; 
    s.the_prop = 5; // THERE YOU GO 
    return s.the_prop; 
} 

cf MSDN, declspec(property).

+0

Tuttavia, questo è ottimo per chi fa progetti di piattaforma non X con MSVC! buona scoperta :) – jmasterx

+0

whoa, non ho mai sentito parlare di questo ... –

37

ATTENZIONE: Questa è una risposta ironica ed è terribile !!!

Sì, è una sorta di possibile :)

template<typename T> 
class Property 
{ 
private: 
    T& _value; 

public: 
    Property(T& value) : _value(value) 
    { 
    } // eo ctor 

    Property<T>& operator = (const T& val) 
    { 
     _value = val; 
     return *this; 
    }; // eo operator = 

    operator const T&() const 
    { 
     return _value; 
    }; // eo operator() 
}; 

quindi dichiarare la classe, dichiarando proprietà per i vostri membri:

class Test 
{ 
private: 
    std::string _label; 
    int   _width; 

public: 
    Test() : Label(_label) 
      , Width(_width) 
    { 
    }; 

    Property<std::string> Label; 
    Property<int>   Width; 
}; 

E chiama C# stile!

Test a; 
a.Label = "blah"; 
a.Width = 5; 

std::string label = a.Label; 
int width = a.Width; 
+9

Ho provato questo in passato anche se ora tendo ad evitarlo perché le persone che leggono il codice non si rendono conto che non è solo un campo pubblico in quanto non è comune in C++ ... Tuttavia sono stato sorpreso di scoprire che il compilatore di solito è abbastanza buono da renderlo altrettanto efficace quanto asserendo direttamente sul campo. – jcoder

+0

Sì, quindi ho avuto il mio "terribile" disclaimer. L'ho pensato un po 'di più e sono sicuro che può essere migliorato in modo che possano essere fornite funzioni personalizzate di set/get per insiemi/ottenere non banali. –

+0

+1 per un uso creativo dei modelli. – paercebal

2

Sì, ma è specifico del fornitore. Microsoft ha declspec (proprietà). L'implementazione di C++ Builder è un po 'più avanzata (tramite una parola chiave __property specifica del fornitore) in quanto potresti avere accessoristi indicizzati (che possono essere di qualsiasi tipo desideri).

anche controllare questo fuori (senza affidarsi a vendor parole chiave specifiche): risposta http://www.codeproject.com/KB/cpp/cpp_property_indexer.aspx

1
#include <iostream> 
#include <string> 

using namespace std; 

// ------------------------------------------------------------------ 

#define PROPERTY_GET_SET(CLASS, NAME, TYPE) GetSetProperty<CLASS, TYPE> NAME() { return GetSetProperty<CLASS, TYPE>(this, &CLASS::get_##NAME, &CLASS::set_##NAME); } 
#define PROPERTY_GET(CLASS, NAME, TYPE)  GetProperty<CLASS, TYPE> NAME() { return GetProperty<CLASS, TYPE>(this, &CLASS::get_##NAME); } 
#define PROPERTY_SET(CLASS, NAME, TYPE)  SetProperty<CLASS, TYPE> NAME() { return SetProperty<CLASS, TYPE>(this, &CLASS::set_##NAME); } 

template <typename CLASS, typename TYPE> 
struct GetSetProperty { 
    typedef TYPE (CLASS::*Getter_t)() const; 
    typedef void (CLASS::*Setter_t)(TYPE); 
    GetSetProperty(CLASS* instance, Getter_t getter, Setter_t setter) : m_instance(instance), m_getter(getter), m_setter(setter) {} 
    operator TYPE() const { return (this->m_instance->*this->m_getter)(); } 
    GetSetProperty<CLASS, TYPE>& operator=(TYPE value) { (this->m_instance->*this->m_setter)(value); return *this; } 
    CLASS* const m_instance; 
    const Getter_t m_getter; 
    const Setter_t m_setter; 
}; 

template <typename CLASS, typename TYPE> 
struct GetProperty { 
    typedef TYPE (CLASS::*Getter_t)() const; 
    GetProperty(CLASS* instance, Getter_t getter) : m_instance(instance), m_getter(getter) {} 
    operator TYPE() const { return (this->m_instance->*this->m_getter)(); } 
    CLASS* const m_instance; 
    const Getter_t m_getter; 
}; 

template <typename CLASS, typename TYPE> 
struct SetProperty { 
    typedef void (CLASS::*Setter_t)(TYPE); 
    SetProperty(CLASS* instance, Setter_t setter) : m_instance(instance), m_setter(setter) {} 
    SetProperty<CLASS, TYPE>& operator=(TYPE value) { (this->m_instance->*this->m_setter)(value); return *this; } 
    CLASS* const m_instance; 
    const Setter_t m_setter; 
}; 

template <typename CLASS, typename TYPE> 
ostream& operator<<(ostream& ostr, const GetSetProperty<CLASS, TYPE>& p) { ostr << (p.m_instance->*p.m_getter)(); return ostr; } 

template <typename CLASS, typename TYPE> 
ostream& operator<<(ostream& ostr, const GetProperty<CLASS, TYPE>& p) { ostr << (p.m_instance->*p.m_getter)(); return ostr; } 

// ------------------------------------------------------------------ 

class Dummy 
{ 
public: 

    Dummy() : m_value1(42) {} 

    PROPERTY_GET_SET(Dummy, Value1, int); 
    PROPERTY_GET_SET(Dummy, Value2, const string&); 

protected: 

    virtual int   get_Value1() const { return this->m_value1; } 
    virtual void   set_Value1(int value) { this->m_value1 = value; } 

    virtual const string& get_Value2() const { return this->m_value2; } 
    virtual void   set_Value2(const string& value) { this->m_value2 = value; } 

private: 

    int m_value1; 
    string m_value2; 
}; 


int main(int argc, char* argv[]) { 

    Dummy d; 

    cout << d.Value1() << endl; 
    d.Value1() = 3; 
    cout << d.Value1() << endl; 

    cout << d.Value2() << endl; 
    d.Value2() = "test"; 
    cout << d.Value2() << endl; 

    return 0; 
} 

// ------------------------------------------------------------------ 
4

di Moo-Juice sembra davvero cool, ma ha un difetto: non è possibile utilizzare queste proprietà come normali espressioni di tipo T, come è possibile in C#.

Per esempio,

  • a.text.c_str() non verrà compilato (‘class Property<std::basic_string<char> >’ has no member named ‘c_str’)
  • std::cout << a.text non verrà compilato né (template argument deduction/substitution failed)

vorrei suggerire il seguente miglioramento al template<typename T> class Property:

T& operator()() 
{ 
    return _value; 
} 
T const& operator()() const 
{ 
    return _value; 
} 

Poi si può accedere ai membri della struttura con (), come ad esempio:

char const *p = a.text().c_str(); 

Ed è possibile utilizzare la proprietà nelle espressioni in cui il tipo deve essere dedotto:

std::cout << a.text(); 
0

Perché non usare linguaggio C# invece di C++ per lo sviluppo nativo? Per questo è possibile utilizzare l'utilità IL2BC per generare codice nativo da sorgente C# e/o codice byte MSIL?

IL2BC si possono trovare in questo sito

http://csnative.codeplex.com