首先,我的最新编码是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; }
};
答案 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);
这也很好地将持有和解析数据的问题分成了不同的类。