想象一下,你有一个包含几十个私有成员变量的类。每个成员变量都有一个公共getter和一个setter函数:
class Foo
{
public:
int GetA() const { return m_a; }
:
int GetZ() const { return m_z; }
void SetA(int val) { m_a = val; }
:
void SetZ(int val) { m_z = val; }
private:
int m_a;
:
int m_z
};
现在我们有了第二个类,它由Foo(以及其他)组成:
class Bar
{
private:
// some instances of other classes of about the same complexity as Foo
Foo m_foo;
};
因此,Bar本质上是一个将单个实体中其他类的实例绑定在一起的类。
传递Bar实例的函数将要访问m_foo
,以便它们可以调用其getter和setter函数。考虑到Scott Meyers在Effective C ++(第3版 - 第28项)中的建议,我不愿意添加一些东西,这些东西会向m_foo返回一个'句柄',例如。
Foo& GetFoo() const { return m_foo; } // dubious const, I know
除了在Bar中复制每一个getter和setter之外,我还有其他选择吗?
我正在使用一些遗留代码,这些代码很懒,可以让'm_foo'公开!但这违背了斯科特的其他一些建议(在这种情况下,第22项 - “声明数据成员私有”)。
出于这种约束的方式吗?
答案 0 :(得分:2)
您应该将数据成员公开。
无论如何,它已经在概念上是公开的,如果你给你描述的Bar getters和setter。这同样适用于getter返回引用的任何getter / setter对。 (除了你可以包括前/后挂钩,但这是一个单独的问题而不是封装。)
答案 1 :(得分:0)
如果你现在无论如何都有getter和setter这样的大类,我认为返回对该对象的引用并不是一个问题,毕竟在它们之间还有一层 - 你基本上仍然可以控制所设置的内容/进入Foo。
OTOH也许如果你设计的课程有很多公共属性,也许你应该重新考虑你的设计,课堂上的东西越多越笨重。
编辑:也许您可以更改公共成员的数据结构并将其放在某种地图中?这样它至少可以节省一些写作。 : - )get("propertyname")
set("propertyname",value)
答案 2 :(得分:0)
嗯,我不愿意。阅读here为什么这是一个坏主意。想象一下,你有一个包含几十个私有成员变量的类。每个成员变量都有一个公共getter和一个setter函数。
答案 3 :(得分:0)
不是,不。您可以为foo中的每个getter或setter创建转发getter和setter。你可以将foo实例公开,或者你可以为foo创建一个getter和setter。
一般来说,我发现,面对这种情况时,最好重新审视我在foo和bar中封装数据的原因。通常我会发现可以将foo分成多个类,然后将需要访问foo数据的每个部分的函数作为方法移动到适当的类中。这导致变量实际上是其类的私有成员变量,并且不需要setter和getter。这就是面向对象编程应该如何工作的方式。
有关对遗留代码执行此操作的良好指南,请查看Martin Fowler的重构。