2010-11-19 13 views
17

In C#/.NET Sie etwas tun können:C# -ähnliche Eigenschaften in nativem C++?

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

Allerdings ist der obige Code nicht tatsächlich mit der Textzeichenfolge direkt Verrückt interagieren, verwendet es eine get- und set-Eigenschaft. In ähnlicher Weise können schreibgeschützte Eigenschaften verwendet werden.

Gibt es eine Möglichkeit, etwas ähnliches in nativen C++ zu tun? (Nicht C++)

+0

Ich bin kein Experte gefunden werden, aber warum lassen Sie nicht 'someThing.text' ein öffentliches Mitglied sein, wenn Sie es wie ein behandeln sind sowieso ? – flies

+2

Verfügbarmachen von Mitgliedern (auch als schreibgeschützt) über Getter und Setter ist schlecht OO. Sie legen die innere Repräsentation Ihres Objekts der Welt offen. Selbst wenn dies durch die Verwendung von Methoden (die hinter dem syntaktischen Zucker der Eigenschaften verborgen sind) leicht geschützt ist, stellt es eine öffentliche API bereit, die gepflegt werden muss. Die Frage ist, warum versuchen Sie, Ihre Mitglieder zu entlarven? Objekt sollte die interne Repräsentation verwenden, um Aufgaben auszuführen, die es nicht für andere Personen zur Verfügung stellt, Aufgaben auszuführen. Anstatt die Implementierung verfügbar zu machen, legen Sie eine Aktionsmethode offen, die die Repräsentation verwendet. –

+0

Ich frage den Nutzen der Zahlung einer Effizienzkosten für die Verschleierung des Codes. –

Antwort

15

in .NET-Objekte sind syntaktischer Zucker für die realen get und set Funktionen, die hinter den Kulissen emittiert werden (in der Tat sind sie mehr als syntaktischer Zucker, weil Eigenschaften in dem sich ergebenden IL emittiert werden und könnte verwendet mit Reflexion). In C++ müssten Sie also diese Funktionen explizit schreiben, da es keine solche Eigenschaft gibt.

+0

Aber woher weiß es, ob die Benutzer will bekommen oder setzen? Muss die Überladung des Operators verwendet werden? – jmasterx

+1

Wenn es sich auf der linken Seite des Zuweisungsoperators ('=') befindet, setzen Sie, wenn es auf der rechten Seite ist, und der Compiler ist schlau genug, das herauszufinden. –

+0

Wenn Sie zwei Funktionen schreiben, die eine Referenz zurückgeben, und eine, die eine Konstante const zurückgibt, ist sehr nützlich, der Compiler wird herausfinden, wann er welche aufrufen soll. Dies erlaubt es jedoch, diese Aufrufe an beliebigen Stellen (in const-Funktionen) auszuführen. – Jbad26

0

Nein, gibt es nicht.

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

Eine Eigenschaft in .NET ist im Zusammenhang mit einem get und/oder einer set Member-Funktion, also ist es wirklich nur syntaktischer Zucker: Sie würden nur Getter und Setter-Funktionen erstellen. Die nächstgelegene Sie mit C++ erhalten können, ist eine Überlastung zu verwenden, um die Getter und Setter den gleichen Namen zu geben:

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

Offensichtlich werden Sie noch Klammer für den Anruf zu bieten haben:

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

Ich warne Sie: Es ist nicht nativ C++; ist es nur Microsoft-spezifische. Aber Sie können declspec(property) verwenden:

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

Dennoch ist das großartig für diejenigen, die nicht X-Plattform-Projekte mit MSVC machen! guter Fund :) – jmasterx

+0

Whoa, ich habe noch nie davon gehört ... –

37

ACHTUNG: Dies ist eine ironische Antwort und ist schrecklich !!!

Ja, es ist eine Art möglich :)

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

dann Ihre Klasse deklarieren, Eigenschaften für Ihre Mitglieder erklärt:

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

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

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

Und nennen C# Art!

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

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

Ich habe das in der Vergangenheit versucht, obwohl ich jetzt dazu tendiere, es zu vermeiden, weil Leute, die den Code lesen, nicht erkennen, dass es nicht nur ein öffentliches Feld ist, wie es nicht üblich ist in C++ ... Allerdings war ich überrascht zu finden, dass der Compiler normalerweise gut genug ist, um dies genauso effizient zu machen, wie direkt in das Feld zu gelangen. – jcoder

+0

Ja, daher hatte ich meinen "schrecklichen" Haftungsausschluss. Ich habe darüber nachgedacht und bin mir sicher, dass es verbessert werden kann, so dass benutzerdefinierte Set/Get-Funktionen für nicht-triviale Sets/Gets bereitgestellt werden können. –

+0

+1 für eine kreative Verwendung von Vorlagen. – paercebal

2

Ja, aber es ist herstellerspezifisch. Microsoft hat declspec (Eigenschaft). Die Implementierung von C++ Builder ist etwas fortgeschrittener (über ein herstellerspezifisches __property-Schlüsselwort), da Sie indizierte Accessoren haben könnten (die von jedem gewünschten Typ sein können).

Auch diese Check-out (ohne bestimmte Schlüsselwörter auf Anbieter verlassen): 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

Moo-Saft Antwort sieht wirklich cool aus, hat aber einen Nachteil: Sie können diese Eigenschaften nicht wie normale Ausdrücke vom Typ verwenden T, wie Sie in C# können.

Zum Beispiel

  • a.text.c_str() kompiliert nicht (‘class Property<std::basic_string<char> >’ has no member named ‘c_str’)
  • std::cout << a.text nicht kompiliert entweder (template argument deduction/substitution failed)

würde ich die folgende Erweiterung template<typename T> class Property vorschlagen:

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

Dann können Sie die Mitglieder der Eigenschaft Zugriff mit (), wie zum Beispiel:

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

Und Sie können die Eigenschaft in Ausdrücken verwenden, wo der Typ abgeleitet werden muss:

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

Warum nicht C# Sprache zu verwenden, anstelle von C++ für native Entwicklung? Dazu können Sie IL2BC-Dienstprogramm verwenden, um nativen Code aus C# -Quelle und/oder MSIL-Byte-Code zu generieren?

IL2BC kann an dieser Stelle

http://csnative.codeplex.com