Const引用字段作为C ++类中的readonly属性

时间:2017-09-18 08:58:03

标签: c++ oop properties reference design-principles

在C ++类中使用const引用字段作为只读getter是不是很好?

我的意思是,这段代码是否符合良好做法?

class check{
private:
    int _x;
public:
    const int& x = _x;
    void setX(int v){
        _x = v;
    }
};

它非常像C#属性,恕我直言,并且在类使用代码中非常简单和干净:

  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';

4 个答案:

答案 0 :(得分:19)

  

这段代码是否符合良好做法?

不是真的,因为它会带来不必要的复杂性和空间开销。

此外,无论访问的值是什么,您都无法执行运行时检查和/或断言。

此外,生命周期和语义会发生什么?

尝试将代码中的一个check分配给另一个,看看会发生什么。分配不正确,因为该类是不可分配的。您应该提供一个复制和移动构造函数来处理引用,这样它就不会引用旧对象的数据成员。

最好直接使用_x并使用简单的内联getter函数。

PS:C#-like properties in native C++?

答案 1 :(得分:6)

一般来说,不是是一种良好的做法。

  

imho,在课堂使用代码中非常简单和干净。

为什么要更清晰,更容易?

  • 您引入了另一个变量成员(无用的开销)。 (通常,引用将作为附加成员指针实现)。
  • 这使代码难以维护。您实际上是在变量成员之间创建依赖关系。
  • 它在分配和复制操作中产生问题。如何复制操作?

“经典”方法听起来更清晰,例如:

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不会引入比“参考方法”更多的开销。此外,它可以被编译器高度优化(因为代码简单)。
  • 空间复杂性:它不会引入额外的数据成员。

答案 2 :(得分:4)

你提出的建议总的来说是一个坏主意:

  • 您无法通过任何处理来实现该属性(例如,使用[x,y]可以存储坐标的getter,然后决定将实现更改为使用[angle,radius],同时保持相同的公共接口)。
  • 使用const成员变量涉及空间开销,与内联getter相比,不会给您带来任何性能优势。
  • 这不是惯用的。
  • 一旦你发表了你的课程,而其他人开始使用它,你就会坚持下去:改为使用方法为时已晚。

如果您对属性的意图是使代码更简洁,则不必在函数名称中使用“get”和“set”;这是一种老式的做法。您可以使用“属性”的实际名称作为函数名称,并且可以重载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;一种实现Fluent interface习语的方法。

答案 3 :(得分:1)

当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 ++中尝试模拟“属性语法”的几乎所有事情都会以这种或那种方式落空。大多数解决方案要么花费你的记忆,要么它会有一些限制,使它比有用的更麻烦。

只要学会与吸气者和二传手一起生活。 吸气剂和制定者是良好做法。 它们很短,很简单,很灵活,通常很适合内联,每个人都理解他们做的事情等等。