С# -подобные свойства на языке С++?
В С#/.NET вы можете сделать что-то вроде этого:
someThing.text = "blah";
String blah = someThing.text;
Однако вышеупомянутый код фактически не взаимодействует с текстом someThing напрямую, он использует свойство get и set. Точно так же можно использовать свойства только для чтения.
Есть ли способ сделать что-то подобное в native C++? (не С++.NET)
Ответы
Ответ 1
В .NET свойствах синтаксический сахар для реальных get
и set
функций, которые испускаются за кулисами (на самом деле они больше, чем синтаксический сахар, потому что свойства испускаются в результате ИЛ и могут быть использованы с Reflection). Поэтому в С++ вам нужно будет явно писать эти функции, поскольку нет такого понятия, как свойство.
Ответ 2
ПРЕДУПРЕЖДЕНИЕ: Это ответ в уши и ужасно!
Да, это возможно:)
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 ()
};
Затем объявите свой класс, объявив свойства для своих членов:
class Test
{
private:
std::string _label;
int _width;
public:
Test() : Label(_label)
, Width(_width)
{
};
Property<std::string> Label;
Property<int> Width;
};
И вызовите стиль С#!
Test a;
a.Label = "blah";
a.Width = 5;
std::string label = a.Label;
int width = a.Width;
Ответ 3
Я предупреждаю вас: это не родной С++; это только для Microsoft. Но вы можете использовать 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 (свойство).
Ответ 4
Ответ Moo-Juice выглядит очень круто, но имеет недостаток: вы не можете использовать эти свойства, как обычные выражения типа T
, как вы можете в С#.
Например,
-
a.text.c_str()
не будет компилироваться (‘class Property<std::basic_string<char> >’ has no member named ‘c_str’
)
-
std::cout << a.text
не будет компилироваться либо (template argument deduction/substitution failed
)
Я бы предложил следующее улучшение template<typename T> class Property
:
T& operator() ()
{
return _value;
}
T const& operator() () const
{
return _value;
}
Затем вы можете получить доступ к элементам свойств с помощью ()
, например:
char const *p = a.text().c_str();
И вы можете использовать свойство в выражениях, где должен быть выведен тип:
std::cout << a.text();
Ответ 5
Свойство в .NET связано с функцией члена get
и/или set
, поэтому оно действительно просто синтаксическое сахар. Ближе всего вы можете использовать С++, чтобы использовать перегрузку, чтобы дать получателю и настройщику одно и то же имя:
const std::string &test() const { return text_; }
void test(const std::string &value) { text_ = value; }
Очевидно, вам все равно придется указывать скобки для вызова:
someThing.text("blah");
String blah = someThing.text();
Ответ 6
Да, но это конкретный поставщик. У Microsoft есть declspec (свойство).
Реализация С++ Builder немного более продвинута (через ключевое слово __property для конкретного поставщика), в котором вы могли бы индексировать аксессоры (которые могут быть любого типа, которые вы хотите).
Также проверьте это (не полагаясь на ключевые слова поставщика): http://www.codeproject.com/KB/cpp/cpp_property_indexer.aspx
Ответ 7
#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;
}
// ------------------------------------------------------------------
Ответ 8
Нет, нет. Вы просто создадите функции getter и setter:
someThing.setText("blah");
std::string blah = someThing.getText();
Ответ 9
Почему бы не использовать язык С# вместо С++ для собственной разработки? Для этого вы можете использовать утилиту IL2BC для генерации собственного кода из источника С# и/или байт-кода MSIL?
IL2BC можно найти на этом сайте
http://csnative.codeplex.com