descargar - ¿Las propiedades similares a C#en C++ nativo?
c++ manual (10)
En C# / .NET puedes hacer algo como esto:
someThing.text = "blah";
String blah = someThing.text;
Sin embargo, el código anterior no interactúa con la cadena de texto de someThing directamente, usa una propiedad de obtener y establecer. Del mismo modo, se pueden utilizar propiedades de solo lectura.
¿Hay una manera de hacer algo similar en C++ nativo? (no C ++ .NET)
¿Por qué no usar el lenguaje C # en lugar de C ++ para el desarrollo nativo? ¿Para eso puede usar la utilidad IL2BC para generar código nativo de código fuente de C # y / o código de MSIL?
IL2BC se puede encontrar en este sitio
En .NET, las propiedades son azúcar sintáctica para las funciones reales de get
y set
que se emiten detrás de escena (de hecho, son más que azúcar sintáctica porque las propiedades se emiten en la IL resultante y podrían usarse con Reflexión). Así que en C ++ necesitaría escribir explícitamente esas funciones ya que no existe una noción como propiedad.
La respuesta de Moo-Juice parece realmente genial, pero tiene un inconveniente: no puede usar estas propiedades como expresiones normales de tipo T
, como puede hacerlo en C #.
Por ejemplo,
-
a.text.c_str()
no compilará (''class Property<std::basic_string<char> >'' has no member named ''c_str''
) -
std::cout << a.text
tampoco se compilará (template argument deduction/substitution failed
)
Yo sugeriría la siguiente mejora a la template<typename T> class Property
:
T& operator() ()
{
return _value;
}
T const& operator() () const
{
return _value;
}
Luego puede acceder a los miembros de la propiedad con ()
, como por ejemplo:
char const *p = a.text().c_str();
Y puede usar la propiedad en expresiones donde se debe deducir el tipo:
std::cout << a.text();
No no hay. Solo crearías funciones de getter y setter:
someThing.setText("blah");
std::string blah = someThing.getText();
Probablemente, la mejor opción actualmente es usar el __declspec( property( get=get_func_name, put=put_func_name ) ) PropertyType PropertyName
.
- también es apoyado por clang,
- se convierte en su getter / setter cuando se compila (no agregará ninguna nueva variable),
- en uso, es lo más cercano a una propiedad real (puede acceder a la propiedad de una propiedad ...).
Pero si estás usando otros compiladores, podrías usar macros:
#define PROPERTY_GEN(Class, Type, Name, GetMethod, SetMethod) /
class Property_##Name { /
public: /
Property_##Name(Class* parent) : _parent(parent) { } /
Type operator = (Type value) /
{ /
_parent->SetMethod(value); /
return _parent->GetMethod(); /
} /
operator Type() const /
{ /
return static_cast<const Class*>(_parent)->GetMethod(); /
} /
Property_##Name& operator =(const Property_##Name& other) /
{ /
operator=(other._parent->GetMethod()); return *this; /
}; /
Property_##Name(const Property_##Name& other) = delete; /
private: /
Class* _parent; /
} Name { this };
// PROPERTY - Declares a property with the default getter/setter method names.
#define PROPERTY(Class, Type, Name) /
PROPERTY_GEN(Class, Type, Name, get_##Name, set_##Name)
Entonces úsalos como:
class SomeClass
{
public:
PROPERTY(SomeClass, int, Value)
int get_Value() const { return _value; }
void set_Value(int value) { _value = value; }
private:
int _value = 0;
};
int main()
{
SomeClass s, c;
s.Value = 5;
c.Value = 3 * s.Value;
s.Value = c.Value;
}
También puede agregar otras variantes de macro para propiedades de solo lectura, de solo escritura y de no constantes de solo lectura. Para poder acceder a las sub-propiedades a través de ->, puede agregar operadores-> sobrecargas a la macro.
En comparación con __declspec (propiedad (...)) de microsoft, los métodos getter y setter pueden hacerse privados, pero esto no es una ventaja real, ya que el cliente puede necesitar la dirección de un getter / setter a veces. También hay una desventaja de tener una variable _parent adicional para cada propiedad, y tendría que definir explícitamente los constructores de copia para las clases primarias si se usan.
Sí, pero es específico del vendedor. Microsoft tiene declspec (propiedad). La implementación de C ++ Builder es un poco más avanzada (a través de la palabra clave __property específica del proveedor) en cuanto a que podría tener indexadores de acceso (que pueden ser de cualquier tipo que desee).
También revise esto (sin depender de palabras clave específicas del proveedor): http://www.codeproject.com/KB/cpp/cpp_property_indexer.aspx
Te advierto: no es C ++ nativo; es específico de Microsoft solamente . Pero puedes usar 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;
}
Una propiedad en .NET está asociada con una función de get
y / o set
un miembro, por lo que en realidad es solo azúcar sintáctica. Lo más cercano que puedes conseguir con C ++ es usar la sobrecarga para dar el mismo nombre al captador y al configurador:
const std::string &test() const { return text_; }
void test(const std::string &value) { text_ = value; }
Obviamente, todavía tendrá que proporcionar paréntesis para la llamada:
someThing.text("blah");
String blah = someThing.text();
ADVERTENCIA: ¡Esta es una respuesta irónica y es terrible!
Sí, es algo posible :)
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 ()
};
Luego declara tu clase, declarando propiedades para tus miembros:
class Test
{
private:
std::string _label;
int _width;
public:
Test() : Label(_label)
, Width(_width)
{
};
Property<std::string> Label;
Property<int> Width;
};
¡Y llame al estilo C #!
Test a;
a.Label = "blah";
a.Width = 5;
std::string label = a.Label;
int width = a.Width;
#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;
}
// ------------------------------------------------------------------