C++ C++;等价于java最终成员数据
首先,我的最新代码是Java,我不想“用C++编写Java” 这里的交易,我必须创建一个不可变的类。这相当简单。唯一的问题是获取初始值需要一些工作。所以我不能简单地调用initializes来初始化我的成员 那么,创建这样一个类的最佳方式是什么?我如何在C++标准中将我的不可变的/最终的属性暴露给外部世界? 下面是一个示例类:C++ C++;等价于java最终成员数据,c++,class-design,C++,Class Design,首先,我的最新代码是Java,我不想“用C++编写Java” 这里的交易,我必须创建一个不可变的类。这相当简单。唯一的问题是获取初始值需要一些工作。所以我不能简单地调用initializes来初始化我的成员 那么,创建这样一个类的最佳方式是什么?我如何在C++标准中将我的不可变的/最终的属性暴露给外部世界? 下面是一个示例类: class Msg { private: int _rec_num; int _seq; string text;
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; }
};
在终结器上 没有,你必须模仿它。可以使用清理功能,也可以将所有资源封装在类中。编译器将在应用程序中放置静态机制来调用RAII类上的析构函数——即,当它们超出范围时,资源将通过析构函数释放 关于不变性和初始化 通常情况下,如果某个对象是不可变的,并且该类的所有成员都是常量,那么只有在初始化该类时才能“写入”它们。但是,在您的情况下,这可能是不可能的
我建议您收集所有资源,并在拥有这些资源后初始化类(通过带有const成员的非默认构造函数)。另一种选择(我不同意)是使用一个mutator函数,该函数“声称”是const-correct,但会写入const值以进行一次性构造后初始化 您走的是正确的道路——对所有事情都使用getter,没有任何setter,您的类实际上是不可变的 不过,不要忘记一些常见情况——您可能希望将operator=()方法声明为private,而不是实现它,这样就不会有人用默认编译器生成的赋值运算符重写对象,等等
// does this look like proper C++?
int get_rec_num() { return _rec_num; }
你应该使用
int get_rec_num() const { return _rec_num; }
(请参阅
const
,它允许调用const对象上的成员)。我会将不可变成员标记为“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
注意:
您应该将任何不会更改类内部状态的成员函数设置为“const”;因为这将允许您使用const对象调用它们
您应该避免在头文件中包含using std::string;因为任何包含标题的人都会被强制使用。C++提供了一些很好的机制来使类不可变。你必须做的是:
- 声明所有公共(可能是受保护的)方法
const
- 将
声明(但不定义)为私有运算符=
const
:
int get_rec_num() const { return _rec_num; }
编辑:由于C++11
,您可以显式删除运算符=
,而不仅仅是不定义它。这明确指示编译器不要定义默认的复制赋值运算符:
Msg& operator=(const Msg&) = delete;
要使变量不可变,必须使用
const
关键字egconst int\u rec\u num
。常量变量只能通过初始化,在构造函数中的任何代码之前调用。这意味着您不能在设置常量成员变量的构造函数中进行任何处理
有两种方法可以解决这个问题,首先可以创建另一个内部类,该类接收缓冲区并将其解析为变量。将此内容的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方法按照其他答案的建议进行操作 首先,可以在构造时高效地初始化成员,即使它们被声明为const(这既不必要也不推荐) 我仍然建议您将此类拆分为两个单独的类(伪代码):
这也很好地将保存和解析数据分为不同的类。实际上应该是“const int get_rec_num()const…”如果按值返回,有什么区别?只要引用不返回,他的类将是不可变的。这是一个很好的惯例,如果我们现在强调它,OP就会学到另一个概念。@Hassan:我支持pmr。那
const
一无所获。如果(将来)用int封装类替换它——比如struct Integer{byte[16]\u data},那么它就没有意义了代码>--程序员不应该编写一致的代码吗?。在C++中懒惰并不是副作用。实际上,它应该是“const int GETReCurnNo.No()const……- Hassan SyedIt没有什么区别,因为对于内置类型,没有常量rof值。无论返回类型是int
还是const int
,都不能写入get\u rec\u num()=7
。我是错了还是最终调用的终结器只是一个残废的析构函数?(假设您使用良好的内存管理,根据需要使用对象优先权或智能指针)。@martin我认为这是有道理的——语法糖;当我在打字时,我自己也有了这个顿悟。然而,它比使用RAII更方便程序员。当我还是一个年轻的程序员时,我渴望C++中的一个终结器。马丁:你的意思是java?如果是这样,那么终结器就不是最终被调用的残缺析构函数。它是一个伪析构函数,最终可能会被调用,也可能不会被调用。而且它不仅仅是“跛脚”——实际上它可以做C++析构函数不能(有效)做的事情,最重要的是
// 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);