C ++ getters / setter编码风格
我一直在C#中编程一段时间,现在我想刷新我的C ++技能。
有课:
class Foo { const std::string& name_; ... };
什么是最好的办法(我只想允许读取访问name_字段):
- 使用getter方法:
inline const std::string& name() const { return name_; }
inline const std::string& name() const { return name_; }
- 使这个领域是公开的,因为它是一个常量
谢谢。
将非常量字段公开化是一个坏主意,因为在未来很难强制错误检查约束和/或增加价值变化的副作用。
在你的情况下,你有一个const字段,所以上述问题不是问题。 使其成为公共领域的主要缺点是您正在locking底层实现。 例如,如果将来想要将内部表示更改为Cstring或Unicodestring或其他内容,那么您将破坏所有的客户端代码。 通过gettor,您可以转换为现有客户端的传统表示forms,同时通过新的gettor向新用户提供更新的function。
我仍然build议像上面放置的那样使用getter方法。 这将最大化您未来的灵活性。
使用getter方法是长寿命类的一个更好的deviseselect,因为它允许您将getter方法replace为将来更复杂的方法。 虽然这似乎不太可能需要一个const值,成本低,可能的好处是巨大的。
顺便说一下,在C ++中,为同名的成员提供getter和setter是一个特别好的主意,因为将来你可以实际改变这两个方法:
class Foo { public: std::string const& name() const; // Getter void name(std::string const& newName); // Setter ... };
在一个公共成员variables中,为每个variables定义一个operator()()
:
// This class encapsulates a fancier type of name class fancy_name { public: // Getter std::string const& operator()() const { return _compute_fancy_name(); // Does some internal work } // Setter void operator()(std::string const& newName) { _set_fancy_name(newName); // Does some internal work } ... }; class Foo { public: fancy_name name; ... };
客户端代码当然需要重新编译,但是不需要修改语法! 显然,这种转换对于常量值也是一样,只需要一个getter。
顺便说一下,在C ++中,有一个const引用成员是有点奇怪的。 你必须在构造函数列表中赋值。 谁拥有对象的实际记忆,以及它的一生如何?
至于风格,我同意其他人,你不想暴露你的私生子。 :-)我喜欢这个setter / getters的模式
class Foo { public: const string& FirstName() const; Foo& FirstName(const string& newFirstName); const string& LastName() const; Foo& LastName(const string& newLastName); const string& Title() const; Foo& Title(const string& newTitle); };
这样你可以做这样的事情:
Foo f; f.FirstName("Jim").LastName("Bob").Title("Programmer");
我认为C ++ 11方法现在更像这样。
#include <string> #include <iostream> #include <functional> template<typename T> class LambdaSetter { public: LambdaSetter() : getter([&]() -> T { return m_value; }), setter([&](T value) { m_value = value; }), m_value() {} T operator()() { return getter(); } void operator()(T value) { setter(value); } LambdaSetter operator=(T rhs) { setter(rhs); return *this; } T operator=(LambdaSetter rhs) { return rhs.getter(); } operator T() { return getter(); } void SetGetter(std::function<T()> func) { getter = func; } void SetSetter(std::function<void(T)> func) { setter = func; } T& GetRawData() { return m_value; } private: T m_value; std::function<const T()> getter; std::function<void(T)> setter; template <typename TT> friend std::ostream & operator<<(std::ostream &os, const LambdaSetter<TT>& p); template <typename TT> friend std::istream & operator>>(std::istream &is, const LambdaSetter<TT>& p); }; template <typename T> std::ostream & operator<<(std::ostream &os, const LambdaSetter<T>& p) { os << p.getter(); return os; } template <typename TT> std::istream & operator>>(std::istream &is, const LambdaSetter<TT>& p) { TT value; is >> value; p.setter(value); return is; } class foo { public: foo() { myString.SetGetter([&]() -> std::string { myString.GetRawData() = "Hello"; return myString.GetRawData(); }); myString2.SetSetter([&](std::string value) -> void { myString2.GetRawData() = (value + "!"); }); } LambdaSetter<std::string> myString; LambdaSetter<std::string> myString2; }; int _tmain(int argc, _TCHAR* argv[]) { foo f; std::string hi = f.myString; f.myString2 = "world"; std::cout << hi << " " << f.myString2 << std::endl; std::cin >> f.myString2; std::cout << hi << " " << f.myString2 << std::endl; return 0; }
我在Visual Studio 2013中对此进行了testing。不幸的是,为了使用LambdaSetter内部的底层存储,我需要提供一个“GetRawData”公共访问器,这可能导致破坏封装,但是您可以将其保留并提供自己的存储容器T或者只是确保你唯一使用“GetRawData”的时候是你正在编写一个自定义的getter / setter方法。
即使这个名字是不可变的,你仍然可以select计算它,而不是把它存储在一个字段中。 (我知道这对于“名字”来说是不太可能的,但是让我们以一般情况为目标。)因此,即使是常量字段也是最好的,
class Foo { public: const std::string& getName() const {return name_;} private: const std::string& name_; };
请注意,如果您要更改getName()
以返回计算值,则无法返回const ref。 没关系,因为它不需要对调用者进行任何更改(模重新编译)。
避免使用公共variables,除了基本上是C风格结构的类。 进入这只是一个不好的做法。
一旦你定义了类接口,你可能永远不能改变它(除了添加它),因为人们会build立它并依靠它。 公开一个variables意味着你需要拥有这个variables,并且你需要确保它具有用户需要的东西。
现在,如果你使用getter,你有希望提供一些信息,目前保存在这个variables中。 如果情况发生变化,并且您不希望始终保持该variables,则可以更改访问权限。 如果需求改变了(我已经看到了一些非常奇怪的需求变化),你大多需要这个variables的名字,但有时候是variables中的名字,你可以改变getter。 如果你把公开的variables,你会被卡住了。
这并不总是会发生,但是我发现,写一个快速的获取者要比分析情况看我是否会后悔让variables公开(后来冒险错了)要容易得多。
使成员variables私人化是一个很好的习惯。 任何有代码标准的商店可能会禁止偶尔的成员variables公开,任何有代码评论的商店都可能会批评你。
无论什么时候写作都不要紧,就要进入更安全的习惯。
从devise模式理论; “封装什么变化”。 通过定义一个“吸气”,就可以很好地遵守上述原则。 因此,如果成员的实现表示将来发生变化,则可以在从“getter”返回之前对成员进行“按摩”。 意味着在“getter”调用的客户端没有代码重构。
问候,