[英]How can I use a private member variable in a non-member function, when the variable happens to be a pointer?
本质上,我的问题是我正在使用的库中的函数(此代码中的函数Foo)需要指向对象(Object * mbar)的指针作为参数。 但是,mbar是bar的私有成员变量。
通常,我只使用getter并按值传递,但是如果传递指针,则将直接访问资源,这将破坏封装。 任何代码都可以调用getter并获得自由进行修改的权限。
我想到的第二件事是我可以使用const指针,因为它们不允许修改指向的资源,但是据我所知,我需要修改Foo来接受它,这是不可能的,因为它是一个库函数。
我能想到的最后一件事就是简单地使用Bar的朋友调用FoobarFunction,但是一直有人告诉我,朋友函数是不得已的方法。
有没有办法在不破坏封装的情况下做到这一点?
//Main.cpp
#include "Foobar.h"
int main()
{
Foobar fb;
Bar b;
fb.FoobarFunction(b);
return 0;
}
//Bar.h
#include "Object.h"
class Bar
{
private:
Object* mbar;
};
//Foobar.h
#include "Foo.h"
#include "Bar.h"
class Foobar
{
public:
void FoobarFunction(Bar bar)
{
Foo(bar.mbar);
}
};
您可以将指针设为const,然后在将其传递给库函数时进行强制转换
Foo(const_cast<Object *>(bar.mbar));
如果Foo不尝试修改mbar,这将起作用。 强制转换“仅以名称”删除常量。 尝试修改秘密常量值可能会导致“可怕的事情”。
即使有一种使Bar返回“只读”指针的方法,问题中的代码示例仍然会违反封装。 这种非封装的特殊方式称为功能嫉妒 :数据存在于一个对象中,而另一个对象则在执行大多数数据操作。 更加面向对象的方法是将操作和数据移到同一对象中。
显然,您提供给我们的示例代码比您的实际项目复杂得多,所以我不知道重组代码的最明智的方法。 这里有一些建议:
将FoobarFunction移至Bar:
class Bar { private: Object* mbar; public: void FoobarFunction() { Foo(mbar); } };
使用依赖注入 。 在创建Bar之前初始化mbar,然后将mbar传递给Bar的构造函数。
int main() { Object *mbar; Foobar fb; Bar b(mbar); fb.FoobarFunction(mbar); return 0; }
在此示例中,Bar不再是mbar的“所有者”。 main方法直接创建mbar,然后将其传递给需要它的任何人。
乍一看,此示例似乎违反了我之前提到的准则(数据和行为存储在不同的对象中)。 但是,上述内容与在Bar上创建吸气剂之间存在很大差异。 如果Bar具有getMBar()方法,那么世界上任何人都可以出现并抓住mbar并将其用于他们想要的任何邪恶目的。 但是在上面的示例中,mbar(主)的所有者完全控制了何时将其数据提供给另一个对象/功能。
除C ++外,大多数面向对象的语言都没有“ friend”构造。 根据我自己的经验,依赖注入是解决许多朋友设计要解决的问题的更好方法。
如果成员是私人的,则可能是私人的,原因是...
如果Bar必须是Obj的唯一所有者,则不应公开它,因为对Obj的任何其他更改都可能导致Bar行为不正确。 虽然,如果Bar不必是Obj的唯一所有者,则可以将getter使用依赖项注入并将其从外部传递给Bar,这样您以后也可以将其传递给foo
。
我认为您应该避免的解决方案是在Bar内部调用foo。 这可能违反了单一责任原则
我相信在这种情况下您可以使用朋友方法。 我将向您介绍一个FAQ ,该FAQ声称朋友对于封装并不总是不好的。
没有! 如果使用得当,它们会增强封装性。
当两个半部分具有不同数量的实例或不同的生存期时,通常需要将一个类分成两半。 在这些情况下,这两个半部通常需要彼此直接访问(这两个半部以前属于同一类,因此您并没有增加需要直接访问数据结构的代码量;只是简单地改组了代码分为两类,而不是一类)。 实现此目的最安全的方法是使两半成为朋友。
如果您使用刚才描述的朋友,则将私人物品保密。 不了解这一点的人通常会天真地努力避免在上述情况下使用友谊,并且实际上他们实际上破坏了封装。 他们要么使用公共数据(怪诞!),要么通过public get()和set()成员函数使数据在两半之间可访问。 仅当从类外部(从用户的角度来看)私有数据“有意义”时,才可以为私有数据使用公共get()和set()成员函数。 在许多情况下,这些get()/ set()成员函数几乎与公共数据一样糟糕:它们(仅)隐藏私有数据的名称,但它们没有隐藏私有数据的存在。
同样,如果将朋友函数用作类的公共访问函数的语法变体,则它们不会违反封装,而成员函数不会违反封装。 换句话说,类的朋友不会违反封装障碍:与类的成员函数一起,它们是封装障碍。
(许多人认为朋友功能是类之外的东西。相反,请尝试将朋友功能视为类的公共接口的一部分。类声明中的朋友功能不会违反封装,就像公共成员功能会违反封装一样封装:在访问类的非公共部分方面,两者具有完全相同的权限。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.