在 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 是 良好做法 。 它们很短、很简单、很灵活,它们通常是内联的好候选者,每个人都明白它们的作用等等。