在 C++ class 中,Const 引用字段为只读 属性
Const reference field as readonly property in C++ class
在 C++ classes 中将 const 引用字段用作只读字段 getter 好吗?
我的意思是,此代码是否符合良好做法?
class check{
private:
int _x;
public:
const int& x = _x;
void setX(int v){
_x = v;
}
};
它的工作方式非常像 C# 属性,恕我直言,并且在 class 使用代码中非常简单和干净:
check s;
int i;
std::cin >> i;
s.setX(i);
std::cout << s.x << '\n';
s.setX(7);
// s.x = i; // Error
std::cout<<s.x<<'\n';
do this code meet good practices?
不一定,因为它引入了不必要的复杂性和 space 开销。
此外,无论访问的值是什么,您都无法执行运行时检查 and/or 断言。
此外,生命周期和语义会怎样?
尝试将代码中的一个 check
分配给另一个,看看会发生什么。赋值格式错误,因为 class 是不可赋值的。您应该提供一个复制和移动构造函数来处理引用,这样它就不会引用旧对象的数据成员。
最好直接使用 _x
并使用简单的内联 getter 函数。
PS: C#-like properties in native C++?
一般来说,这不是一个好的做法。
imho, and very easy and clean in class usage code.
为什么要更清楚、更容易?
- 你引入了另一个变量成员(无用的开销)。 (一般情况下,引用会作为一个额外的成员指针来实现)。
- 它使代码更难维护。您实际上是在变量成员之间创建依赖关系。
- 它在分配和复制操作中产生问题。复制操作应该如何工作?
"classic" 方法对我来说听起来更清晰,例如:
class Foo {
public:
void set_num(int value) noexcept { m_num = value; }
int get_num() const noexcept { return m_num; }
void set_string(std::string value) noexcept {
m_str = std::move(value);
}
const std::string& get_string() const noexcept {
return m_str;
}
private:
int m_num;
std::string m_str;
};
从性能的角度来看,应该首选这种方法。
- 时间复杂度:在 内联 函数上调用
get_variable
不会引入比 "reference approach" 更多的开销。此外,编译器可以对其进行高度优化(因为代码简单明了)。
- Space复杂性:不引入额外的数据成员。
你的建议总体上是个坏主意:
- 您不能通过任何处理来实现 属性(例如,对于 getter,您可以使用 [x,y] 存储坐标,然后决定更改实现以使用[角度,半径],同时保持相同的 public 界面)。
- 使用 const 成员变量涉及 space 开销,与内联 getter.
相比,不会给您带来任何性能优势
- 这不是地道的。
- 一旦您发布了您的 class,并且其他人开始使用它,您就会坚持使用它:现在改变它以使用一种方法为时已晚。
如果您使用属性的目的是使代码更简洁,则不必在函数名称中使用单词 "get" 和 "set";那是一种老式的做法。您可以使用 "property" 的实际名称作为函数名称,并且可以重载 getter 和 setter:
class Cheque {
public:
int x() const {
return x_;
}
Cheque & x(int newX) {
x_ = newX;
return *this;
}
private:
int x_;
}
// Usage:
// int amt = myCheque.x(1234);
// Cheque c = Cheque().x(123);
返回 *this
如上代码使您能够使用 method chaining; a way of implementing the Fluent interface 成语。
当 C# 编译一个 属性 时,它被编译成一个 getter 和一个 setter 函数。
这里有一些 C# 代码可以证明这一事实:
using System;
namespace Reflect
{
class Program
{
class X
{
public int Prop { get; set; }
}
static void Main(string[] args)
{
var type = typeof(X);
foreach (var method in type.GetMethods())
{
Console.WriteLine(method.Name);
}
Console.ReadKey();
}
}
}
你的输出应该是:
get_Prop
set_Prop
ToString
Equals
GetHashCode
GetType
get_Prop
是实现getter的函数。
set_Prop
是实现 setter.
的函数
因此,即使您所做的看起来很相似,但根本不一样。
坦率地说,几乎所有你可以尝试在 C++ 中模拟 'property syntax' 的东西都会以这样或那样的方式失败。大多数解决方案要么会消耗您的内存,要么会有一些限制,使它变得麻烦而不实用。
只是学会与 getters 和 setters 一起生活。
吸气剂和 setter 是 良好做法 。
它们很短、很简单、很灵活,它们通常是内联的好候选者,每个人都明白它们的作用等等。
在 C++ classes 中将 const 引用字段用作只读字段 getter 好吗?
我的意思是,此代码是否符合良好做法?
class check{
private:
int _x;
public:
const int& x = _x;
void setX(int v){
_x = v;
}
};
它的工作方式非常像 C# 属性,恕我直言,并且在 class 使用代码中非常简单和干净:
check s;
int i;
std::cin >> i;
s.setX(i);
std::cout << s.x << '\n';
s.setX(7);
// s.x = i; // Error
std::cout<<s.x<<'\n';
do this code meet good practices?
不一定,因为它引入了不必要的复杂性和 space 开销。
此外,无论访问的值是什么,您都无法执行运行时检查 and/or 断言。
此外,生命周期和语义会怎样?
尝试将代码中的一个 check
分配给另一个,看看会发生什么。赋值格式错误,因为 class 是不可赋值的。您应该提供一个复制和移动构造函数来处理引用,这样它就不会引用旧对象的数据成员。
最好直接使用 _x
并使用简单的内联 getter 函数。
PS: C#-like properties in native C++?
一般来说,这不是一个好的做法。
imho, and very easy and clean in class usage code.
为什么要更清楚、更容易?
- 你引入了另一个变量成员(无用的开销)。 (一般情况下,引用会作为一个额外的成员指针来实现)。
- 它使代码更难维护。您实际上是在变量成员之间创建依赖关系。
- 它在分配和复制操作中产生问题。复制操作应该如何工作?
"classic" 方法对我来说听起来更清晰,例如:
class Foo {
public:
void set_num(int value) noexcept { m_num = value; }
int get_num() const noexcept { return m_num; }
void set_string(std::string value) noexcept {
m_str = std::move(value);
}
const std::string& get_string() const noexcept {
return m_str;
}
private:
int m_num;
std::string m_str;
};
从性能的角度来看,应该首选这种方法。
- 时间复杂度:在 内联 函数上调用
get_variable
不会引入比 "reference approach" 更多的开销。此外,编译器可以对其进行高度优化(因为代码简单明了)。 - Space复杂性:不引入额外的数据成员。
你的建议总体上是个坏主意:
- 您不能通过任何处理来实现 属性(例如,对于 getter,您可以使用 [x,y] 存储坐标,然后决定更改实现以使用[角度,半径],同时保持相同的 public 界面)。
- 使用 const 成员变量涉及 space 开销,与内联 getter. 相比,不会给您带来任何性能优势
- 这不是地道的。
- 一旦您发布了您的 class,并且其他人开始使用它,您就会坚持使用它:现在改变它以使用一种方法为时已晚。
如果您使用属性的目的是使代码更简洁,则不必在函数名称中使用单词 "get" 和 "set";那是一种老式的做法。您可以使用 "property" 的实际名称作为函数名称,并且可以重载 getter 和 setter:
class Cheque {
public:
int x() const {
return x_;
}
Cheque & x(int newX) {
x_ = newX;
return *this;
}
private:
int x_;
}
// Usage:
// int amt = myCheque.x(1234);
// Cheque c = Cheque().x(123);
返回 *this
如上代码使您能够使用 method chaining; a way of implementing the Fluent interface 成语。
当 C# 编译一个 属性 时,它被编译成一个 getter 和一个 setter 函数。
这里有一些 C# 代码可以证明这一事实:
using System;
namespace Reflect
{
class Program
{
class X
{
public int Prop { get; set; }
}
static void Main(string[] args)
{
var type = typeof(X);
foreach (var method in type.GetMethods())
{
Console.WriteLine(method.Name);
}
Console.ReadKey();
}
}
}
你的输出应该是:
get_Prop
set_Prop
ToString
Equals
GetHashCode
GetType
get_Prop
是实现getter的函数。
set_Prop
是实现 setter.
因此,即使您所做的看起来很相似,但根本不一样。
坦率地说,几乎所有你可以尝试在 C++ 中模拟 'property syntax' 的东西都会以这样或那样的方式失败。大多数解决方案要么会消耗您的内存,要么会有一些限制,使它变得麻烦而不实用。
只是学会与 getters 和 setters 一起生活。 吸气剂和 setter 是 良好做法 。 它们很短、很简单、很灵活,它们通常是内联的好候选者,每个人都明白它们的作用等等。