c++ 11有c#风格的属性吗?
本文关键字:属性 风格 c++ | 更新日期: 2023-09-27 18:16:29
在c#中,对于带有getter和setter的字段有一个很好的语法糖。此外,我喜欢自动实现的属性,它允许我编写
public Foo foo { get; private set; }
在c++中我必须写
private:
Foo foo;
public:
Foo getFoo() { return foo; }
在c++ 11中是否有这样的概念允许我在这方面有一些语法糖?
在c++中你可以编写你自己的特性。下面是一个使用未命名类实现属性的示例。维基百科的文章
struct Foo
{
class {
int value;
public:
int & operator = (const int &i) { return value = i; }
operator int () const { return value; }
} alpha;
class {
float value;
public:
float & operator = (const float &f) { return value = f; }
operator float () const { return value; }
} bravo;
};
你可以自己写getter &如果您想要持有者类成员访问权限,您可以扩展这个示例代码。
c++没有内置这个功能,您可以定义一个模板来模拟属性的功能:
template <typename T>
class Property {
public:
virtual ~Property() {} //C++11: use override and =default;
virtual T& operator= (const T& f) { return value = f; }
virtual const T& operator() () const { return value; }
virtual explicit operator const T& () const { return value; }
virtual T* operator->() { return &value; }
protected:
T value;
};
定义一个属性:
Property<float> x;
要实现自定义getter/setter只需继承:
class : public Property<float> {
virtual float & operator = (const float &f) { /*custom code*/ return value = f; }
virtual operator float const & () const { /*custom code*/ return value; }
} y;
定义一个只读属性:
template <typename T>
class ReadOnlyProperty {
public:
virtual ~ReadOnlyProperty() {}
virtual operator T const & () const { return value; }
protected:
T value;
};
和使用它在类Owner
:
class Owner {
public:
class : public ReadOnlyProperty<float> { friend class Owner; } x;
Owner() { x.value = 8; }
};
您可以在宏中定义上面的一些,以使其更简洁。
c++语言中没有任何东西可以跨所有平台和编译器工作。
但是,如果你愿意打破跨平台兼容性,并提交到一个特定的编译器,你可能能够使用这样的语法,例如,在Microsoft Visual c++中,你可以做
// declspec_property.cpp
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;
return s.the_prop;
}
在c++ 11中,你可以定义一个Property类模板,并像这样使用它:
class Test{
public:
Property<int, Test> Number{this,&Test::setNumber,&Test::getNumber};
private:
int itsNumber;
void setNumber(int theNumber)
{ itsNumber = theNumber; }
int getNumber() const
{ return itsNumber; }
};
这里列出了Property类模板。
template<typename T, typename C>
class Property{
public:
using SetterType = void (C::*)(T);
using GetterType = T (C::*)() const;
Property(C* theObject, SetterType theSetter, GetterType theGetter)
:itsObject(theObject),
itsSetter(theSetter),
itsGetter(theGetter)
{ }
operator T() const
{ return (itsObject->*itsGetter)(); }
C& operator = (T theValue) {
(itsObject->*itsSetter)(theValue);
return *itsObject;
}
private:
C* const itsObject;
SetterType const itsSetter;
GetterType const itsGetter;
};
您可以通过拥有专用类型的成员并覆盖operator(type)
和operator=
来在一定程度上模拟getter和setter。这是否是个好主意是另一个问题,我要+1
Kerrek SB的回答来表达我的意见:)
也许可以看看我在过去几个小时内组装的属性类:https://codereview.stackexchange.com/questions/7786/c11-feedback-on-my-approach-to-c-like-class-properties
它允许你有这样的属性行为:
CTestClass myClass = CTestClass();
myClass.AspectRatio = 1.4;
myClass.Left = 20;
myClass.Right = 80;
myClass.AspectRatio = myClass.AspectRatio * (myClass.Right - myClass.Left);
正如许多人已经说过的那样,该语言没有内置支持。但是,如果您的目标是Microsoft c++编译器,则可以利用此处记录的Microsoft特定属性扩展。
这是来自链接页面的示例:
// declspec_property.cpp
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;
return s.the_prop;
}
不,c++没有属性的概念。虽然定义和调用getThis()或setThat(value)可能会很尴尬,但您是在向这些方法的使用者声明可能会发生某些功能。另一方面,在c++中访问字段告诉使用者不会发生额外的或意外的功能。属性将使这一点不那么明显,因为属性访问乍一看似乎像一个字段,但实际上像一个方法。
作为题外话,我正在一个。net应用程序(一个非常著名的CMS)中工作,试图创建一个客户会员系统。由于他们对用户对象使用属性的方式,操作会以我没有预料到的方式启动,导致我的实现以奇怪的方式执行,包括无限递归。这是因为它们的用户对象在试图访问像StreetAddress这样简单的东西时调用了数据访问层或一些全局缓存系统。他们的整个体系建立在我称之为财产滥用的基础上。如果他们使用方法而不是属性,我想我可以更快地找出问题所在。如果他们使用了字段(或者至少使他们的属性表现得更像字段),我认为系统会更容易扩展和维护。[编辑]改变了我的想法。我那天过得不太好,有点发脾气。这种清理应该更专业。
基于https://stackoverflow.com/a/23109533/404734,这里有一个带有公共getter和私有setter的版本:
struct Foo
{
class
{
int value;
int& operator= (const int& i) { return value = i; }
friend struct Foo;
public:
operator int() const { return value; }
} alpha;
};
您可能知道,但我将简单地做以下操作:
class Person {
public:
std::string name() {
return _name;
}
void name(std::string value) {
_name = value;
}
private:
std::string _name;
};
这个方法很简单,没有使用任何聪明的技巧,它完成了工作!
问题是有些人不喜欢用下划线前缀他们的私有字段,所以他们不能真正使用这种方法,但幸运的是,对于这些人来说,它真的很直接。:)
get和set前缀并没有使你的API更清晰,反而使它们更冗长,我认为它们没有增加有用信息的原因是,当有人需要使用API时,如果API是有意义的,她可能会意识到没有前缀它能做什么。
还有一件事,很容易理解这些是属性,因为name
不是动词。
最坏的情况是,如果api是一致的,并且该人没有意识到name()
是一个访问器而name(value)
是一个mutator,那么她只需要在文档中查找一次就可以理解模式。
尽管我很喜欢c#,但我认为c++根本不需要属性!
这不是一个确切的属性,但它做你想要的简单的方式:
class Foo {
int x;
public:
const int& X;
Foo() : X(x) {
...
}
};
这里的大X的行为类似于c#语法中的public int X { get; private set; }
。如果你想要完整的属性,我在这里做了第一次尝试来实现它们。
不。但是你应该考虑如果它只是get:set函数,并且在get:set方法中没有执行额外的任务,只是使它成为公共的。
我从多个c++源代码中收集了一些想法,并将其放入一个很好的,仍然相当简单的c++ getter/setter示例中:
class Canvas { public:
void resize() {
cout << "resize to " << width << " " << height << endl;
}
Canvas(int w, int h) : width(*this), height(*this) {
cout << "new canvas " << w << " " << h << endl;
width.value = w;
height.value = h;
}
class Width { public:
Canvas& canvas;
int value;
Width(Canvas& canvas): canvas(canvas) {}
int & operator = (const int &i) {
value = i;
canvas.resize();
return value;
}
operator int () const {
return value;
}
} width;
class Height { public:
Canvas& canvas;
int value;
Height(Canvas& canvas): canvas(canvas) {}
int & operator = (const int &i) {
value = i;
canvas.resize();
return value;
}
operator int () const {
return value;
}
} height;
};
int main() {
Canvas canvas(256, 256);
canvas.width = 128;
canvas.height = 64;
}
输出:new canvas 256 256
resize to 128 256
resize to 128 64
您可以在这里在线测试:http://codepad.org/zosxqjTX
这里有一组宏。这为值类型、引用类型、只读类型、强类型和弱类型提供了方便的属性声明。
class MyClass {
// Use assign for value types.
NTPropertyAssign(int, StudentId)
public:
...
}
你的类真的需要强制一些不变量还是它只是一个成员元素的逻辑分组?如果是后者,你应该考虑把它变成一个结构体并直接访问它的成员。
下面是c++中属性的另一个实现(std=c++17)
propertycpp@github
它提供了一个示例,展示了如何创建属性,或者在试图写入属性时处理构建时异常时作为只读公开可用;显示"default"的示例具有读&写访问权限的属性,动态getter(修改实际值)和动态只读的示例。