当变量恰好是指针时,如何在非成员函数中使用私有成员变量
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);
}
};
简单的出路
您可以将指针设为常量,然后在将其传递给库函数时进行强制转换
Foo(const_cast<Object *>(bar.mbar));
如果Foo不尝试修改mbar,这将起作用。强制转换删除了"名义上的"常量。试图修改一个秘密的常量值可能会导致可怕的事情。
但是真的
即使有一种方法可以让Bar返回一个"只读"指针,问题中的代码示例仍然会违反封装。这种特殊的非封装风格被称为特征嫉妒:数据存在于一个对象中,但另一个对象正在进行大部分数据操作。一种更面向对象的方法是将操作和数据移动到同一个对象中。
很明显,你给我们的示例代码比你的实际项目复杂得多,所以我不知道重组代码的最明智的方法。这里有几个建议:
将FoobarFunction移动到条形:
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的"所有者"。主要方法是直接创建毫巴,然后将其传递给任何需要它的人
乍一看,这个例子似乎违反了我前面提到的准则(数据和行为存储在不同的对象中)。然而,以上和在Bar上创建getter之间有很大的区别。如果Bar有一个getMBar()方法,那么世界上任何人都可以来抓mbar,并将其用于他们想要的任何邪恶目的。但在上面的例子中,mbar(main)的所有者完全可以控制何时将其数据提供给另一个对象/函数。
除了C++之外,大多数面向对象的语言都没有"朋友"结构。根据我自己的经验,依赖注入是解决朋友们设计用来解决的许多问题的更好方法。
如果成员是私有的,那么它可能是私有的是有原因的。。。
如果Bar必须是Obj的唯一所有者,那么它不应该公开它,因为对Obj的任何其他更改都可能导致Bar的行为不正确。尽管如此,如果Bar不必是Obj的唯一所有者,您可以使用依赖项注入将getter放入Bar中,然后从外部将其传递到Bar中,这样以后也可以将其传递给foo
。
我认为你应该避免的一个解决方案是在Bar中调用foo。这可能违反单一责任原则
我认为,在这种情况下,你可以使用朋友的方法。我将向您介绍一个常见问题解答,声称朋友并不完全不适合封装。
不!如果使用得当,它们可以增强封装性。
当类的两半具有不同数量的实例或不同的生存期时,通常需要将类一分为二。在这些情况下,这两半通常需要直接访问对方(这两半过去在同一个类中,所以您没有增加需要直接访问数据结构的代码量;您只是将代码重新排列为两个类,而不是一个类)。实现这一点最安全的方法是让两半成为彼此的朋友。
如果你像刚才描述的那样使用朋友,你会把私人事情保密。不理解这一点的人往往会天真地努力避免在上述情况下使用友谊,而且他们往往会破坏封装。它们要么使用公共数据(怪诞!),要么通过公共get()和set()成员函数在两半之间访问数据。只有当私有数据"时,为私有数据具有公共get()和set()成员函数才是可以的;"有意义";从类外(从用户的角度)。在许多情况下,这些get()/set()成员函数几乎和公共数据一样糟糕:它们隐藏(仅)私有数据的名称,但不隐藏私有数据的存在。
类似地,如果使用友元函数作为类的公共访问函数的语法变体,则它们不会违反封装,就像成员函数违反封装一样。换句话说,类的朋友不会违反封装屏障:与类的成员函数一起,它们就是封装屏障。
(很多人认为友元函数是类外的东西。相反,试着把友元函数看作类公共接口的一部分。类声明中的友元函数并不违反封装,就像公共成员函数违反封装一样:两者在访问类的非公共部分方面具有完全相同的权限。)
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 内置函数可查看CPP中的成员变量
- 是否可以初始化不可复制类型的成员变量(或基类)
- 将包含C样式数组的对象初始化为成员变量(C++)
- 为什么我不能在一个类的不同行中声明和定义成员变量?
- 在循环中按顺序遍历成员变量
- c++类声明时,相同的例程,不同的成员变量类型
- 如何从另一个文件继承私有成员变量和公共函数
- 在C++类中,是否必须初始化作为数组的成员变量
- 如何从子成员函数修改父公共成员变量
- 我可以在 C++ 中将数据成员/变量从其定义之外添加到结构中吗?
- 从私有成员变量的成员方法返回unique_ptr
- 在派生类中使用基类的私有成员变量的最佳方法
- 静态 constexpr 类成员变量对多线程读取是否安全?
- C++:是否可以使用非静态成员变量模板?
- 打印所有继承的类成员变量和方法
- 如何在复杂继承中访问静态成员变量
- 为什么我不能在返回 const 的布尔函数中为类成员变量赋值?C++
- 成员变量与函数概念检查