sch*_*chc 13 c++ effective-c++
Scott Meyers的有效C++在第5章第28项中告诉我们避免将"句柄"(指针,引用或迭代器)返回到对象内部,这绝对是一个好点.
即不要这样做:
class Family
{
public:
Mother& GetMother() const;
}
Run Code Online (Sandbox Code Playgroud)
因为它破坏了封装并允许改变私有对象成员.
甚至不这样做:
class Family
{
public:
const Mother& GetMother() const;
}
Run Code Online (Sandbox Code Playgroud)
因为它可以导致"悬空手柄",这意味着您保留对已经销毁的对象的成员的引用.
现在,我的问题是,有什么好的选择吗?想象一下妈妈很沉重!如果我现在返回母亲的副本而不是参考,GetMother正在成为一个相当昂贵的操作.
你如何处理这种情况?
Mat*_* M. 14
首先,让我重新迭代:最大的问题不是生命周期,而是封装之一.
封装不仅意味着没有人能够在没有意识到内容的情况下修改内部,封装意味着没有人知道如何在类中实现内容,因此只要保持接口相同,就可以随意更改类内部.
现在,您返回的引用是否与之const无关:您不小心暴露了您的Mother内部有一个对象的事实Family类中现在你无法摆脱它(即使你有更好的表示),因为所有你的客户可能依赖它并且必须更改其代码......
最简单的解决方案是按值返回:
class Family {
public:
Mother mother() { return _mother; }
void mother(Mother m) { _mother = m; }
private:
Mother _mother;
};
Run Code Online (Sandbox Code Playgroud)
因为在下一次迭代中我可以在_mother不破坏界面的情况下删除:
class Family {
public:
Mother mother() { return Mother(_motherName, _motherBirthDate); }
void mother(Mother m) {
_motherName = m.name();
_motherBirthDate = m.birthDate();
}
private:
Name _motherName;
BirthDate _motherBirthDate;
};
Run Code Online (Sandbox Code Playgroud)
看看我如何在不改变界面的情况下完全改造内部结构?十分简单.
注意:显然这种转换只是为了效果......
显然,这种封装是以某种性能为代价的,这里有一种紧张,每次你写一个吸气剂时,是否应该首选封装或性能是你的判断.
可能的解决方案取决于您的类的实际设计以及您认为"对象内部"的内容.
Mother只是实现细节,Family可以完全隐藏Family用户Family 被视为其他公共对象的组合在第一种情况下,您应完全封装子对象并仅通过Family函数成员(可能复制Mother公共接口)提供对它的访问:
class Family
{
std::string GetMotherName() const { return mommy.GetName(); }
unsigned GetMotherAge() const { return mommy.GetAge(); }
...
private:
Mother mommy;
...
};
Run Code Online (Sandbox Code Playgroud)
好吧,如果Mother界面非常大,可能会很无聊,但可能这是设计问题(好的界面应该有3-5-7个成员),这将使你以更好的方式重新审视和重新设计它.
在第二种情况下,您仍然需要返回整个对象.有两个问题:
Mother定义)要解决问题1使用界面而不是特定类,要解决问题2使用共享或弱所有权:
class IMother
{
virtual std::string GetName() const = 0;
...
};
class Mother: public IMother
{
// Implementation of IMother and other stuff
...
};
class Family
{
std::shared_ptr<IMother> GetMother() const { return mommy; }
std::weak_ptr<IMother> GetMotherWeakPtr() const { return mommy; }
...
private:
std::shared_ptr<Mother> mommy;
...
};
Run Code Online (Sandbox Code Playgroud)
这又回到了一个基本的 OO 原则:
Tell objects what to do rather than doing it for them.
Run Code Online (Sandbox Code Playgroud)
你需要Mother做一些有用的事情吗?要求Family对象为你做这件事。Class通过对象上方法的参数,将任何外部依赖项封装在一个漂亮的接口(在 C++ 中)中Family。