Java最终成员数据的C ++等价物

时间:2010-03-01 09:17:13

标签: c++ class-design

首先,我的最新编码是Java,我不想“用C ++编写Java”。

这是交易,我必须创建一个不可变的类。这很简单。唯一的问题是获得初始值是一些工作。所以我不能简单地调用初始化来初始化我的成员。

那么创建这样一个类的最佳方法是什么?如何在C ++标准中将我的不可变/最终属性暴露给外界?

这是一个示例类:

class Msg {
    private:
        int _rec_num;
        int _seq;
        string text;
    public:
        Msg(const char* buffer) {
            // parse the buffer and get our member here...
            // ... lots of code
        }

        // does this look like proper C++?
        int get_rec_num() { return _rec_num; }
    };

7 个答案:

答案 0 :(得分:7)

C ++提供了一些很好的机制来使你的类不可变。你必须做的是:

  • 声明所有公开(可能受保护)的方法const
  • 声明(但未定义)operator=为私人

这将确保您的对象在创建后无法修改。现在,您可以使用const方法提供对所需的现在不可变数据成员的访问。您的示例看起来是正确的,只要您将其设为const

int get_rec_num() const { return _rec_num; }

答案 1 :(得分:3)

我将你的不可变成员标记为'const',并在构造函数初始化列表中为它赋值。

我还会在类之外解析缓冲区,并将字符串传递给构造函数。

这样的事情:

class Msg {
  private:
    int _rec_num;
    int _seq;
    const std::string text;
  public:
    Msg(const std::string& str) :
      text(str)
    {

    }

    // does this look like proper C++?
    int get_rec_num() const { return _rec_num; }
};

// parse the buffer and get our parameter somewhere else

NB:

您应该将任何不会将类内部状态更改为“const”的成员函数;因为这将允许你用const对象调用它们。

你应该避免在头文件中包含一个使用std :: string;任何包含你标题的人都会强行使用这个“使用”。

答案 2 :(得分:1)

你走在正确的轨道上 - 为所有事情使用getter,没有任何setter,你的类实际上是不可变的。

不要忘记一些极端情况 - 您可能希望将operator =()方法声明为私有而不实现它,因此有人不能使用默认编译器生成的赋值运算符等来覆盖该对象。

答案 3 :(得分:1)

    // does this look like proper C++?
    int get_rec_num() { return _rec_num; }

你应该使用

    int get_rec_num() const { return _rec_num; }

(参见允许在const对象上调用成员的const。)

答案 4 :(得分:0)

关于终结者

没有,你必须模仿它。通过使用清理功能或将所有资源封装在RAII类中。编译器将在您的应用程序中放置静态机制来调用RAII类的析构函数 - 即,当它们超出范围时,资源将通过析构函数释放。

关于不变性和初始化

通常,如果某些东西是不可变的,const-correct该类将其所有成员都作为const,并且唯一一次“写入”它们就是在初始化类时。但是在您的情况下可能无法实现。

我建议您收集所有资源并初始化类(通过带有const成员的非默认构造函数)。另一种替代方法(我不遵守)是一个mutpon函数,“声称”是const正确但写入const值进行一次性构造初始化。

答案 5 :(得分:0)

要使变量不可变,您必须使用const关键字,例如const int _rec_num。 Const变量只能通过initialisation list初始化,{{3}}在构造函数中的任何代码之前调用。这意味着您不能在构造const成员变量的构造函数中进行任何处理。

你有两种方法,首先你可以创建另一个内部类,它接受一个缓冲区并将其解析为你的变量。将const版本放入MSG类并将其放入初始化列表中:

class MsgInner
{
    public:
    int _rec_num;

    Msg(const char* buffer) {
        // Your parsing code
    }
};

class Msg
{
    public:
    const MsgInner msg;

    Msg(const char* buffer) : msg(buffer)
    { // any other code }
};

这可能不是那么“标准”,但这是另一种观点。否则你也可以使用get方法建议的其他答案。

答案 6 :(得分:0)

首先,可以在构造时有效地初始化成员,即使它们被声明为const(既不必要也不推荐)。

我仍然建议您将此类拆分为两个单独的类(伪代码):

// Msg: pure data object; copy constructible but not modifiable.
class Msg
{
public:
  Msg(int rec_num, ...)
    : rec_num_(rec_num)
    ...
  {}

  int rec_num() const
  { return rec_num_; }
  ...
private:
  // prevent copying
  Msg& operator=(Msg const&);
private:
  int rec_num_;
}; 

// MsgParser: responsible for parsing the buffer and
// manufacturing Msg's.
class MsgParser
{
public:
  static Msg Parse(char const* buffer)
  {
     ... parse ...
     return Msg(...);
  }
};

// Usage
Msg const msg = MsgParser::Parse(buffer);

这也很好地将持有和解析数据的问题分成了不同的类。