C++中const公共字段与getter方法的区别

12

我想为一个特定类的每个对象添加唯一ID(在单个会话中)。一种解决方案是使用工厂函数来递增某些静态计数器。更简单的方法是将该计数器添加到类本身中,例如:

class fooWithUniqueId {
public:
    fooWithUniqueId() : id(next_id++) {...};        
    long id;

private:
    static long next_id = 0;
}

然而,一个缺陷是id字段是公共的,并且可以被调用者更改,违反了其唯一性。传统的做法(至少在我看来)是将id设置为私有,使用getter函数来访问它:

class fooWithUniqueId {
public:
    fooWithUniqueId() : id(next_id++) {...};                
    long getId() const { return id; };

private:
    long id;
    static long next_id = 0;
}

但我正在考虑不同的方法。我可以将id定义为公共的类常量字段:

class fooWithUniqueId {
public:
    fooWithUniqueId() : id(next_id++) {...};                
    const long id;

private:
    static long next_id = 0;
}

我更喜欢这种方法,因为我不需要每次调用getId()获取id,可以将其作为映射中的键(由于复制构造函数正确初始化了复制对象的id)。我能想到的一个缺点是不能在fooWithUniqueId对象之间实现赋值,虽然目前我不需要这个功能。

  • 各种方法的利弊是什么(getter函数/const字段)?
  • 假设我使用'const'方法,是否有办法稍后实现赋值运算符而不破坏代码?

谢谢,Boaz


1
你确定在赋值运算符中也要复制ID吗?毕竟,你的ID必须是唯一的。 - Vlad
@Vlad:你可能是对的,目前我并不打算实现一个赋值运算符。我问这个问题是因为我不想在需要时大量重构代码。 - bavaza
2个回答

7
我可以将id用作映射中的键(因为复制构造函数可以正确地初始化副本对象的id)。
"正确地"是什么意思?默认的复制构造函数会复制ID,无论它是存储在私有成员变量还是公共成员变量中,你最终会得到两个共享相同ID的对象。这可能不是你想要的。
一般来说,在C++中,你永远不应该使用公共变量,因为它违反了适当的封装。总是使用一个(内联的)getter方法。唯一的缺点是你需要输入更多的字符。
我强烈建议你坚持最佳实践并使用具有getter函数的私有字段。

15
一个作用域常量如何破坏封装性? - Šimon Tóth
3
@Ferdinand:无意冒犯,但我认为从不使用公共字段相当严格,特别是因为我打算将该特定类用作POD,并且它可能有许多字段。您真的建议为每个字段编写getter / setter吗? - bavaza
最好使用结构体将所有字段分组并拥有一个Setter/Getter来获取和设置结构体字段。而且不要使用inline。编译器必须自行决定在99%的情况下是将函数内联还是不内联。http://www.parashift.com/c++-faq-lite/inline-functions.html - Andrew
1
@Let_Me_Be:我写的是“变量”,不是“常量”。 - Ferdinand Beyer
@Andrew:当然,声明内联函数只是给编译器一个提示,让它决定是否将其内联。但如果没有这个提示,典型的编译器将永远不会将其内联。当然,你可能认为内联是“过早优化”的一种情况。另一方面,没有理由内联简单的getter函数。 - Ferdinand Beyer
显示剩余3条评论

7

如果设计表明某个类的公共成员常量永远不会改变,那么在类中拥有这样的常量是可以的。唯一的id就是这样的情况。

对我来说,const成员禁止赋值的事实似乎是一个优点。如果你将一个实例分配给另一个实例,那么id将不再是唯一的!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接