我正在尝试设计一个库,只向调用者打开几个接口,而不会弄乱自己的内部访问控制。这样做的正确方法是什么?
例如,这是库:
namespace ControlledLib {
class ThinkTrack1 {
friend class DeepThought;
friend class ThinkTrack2;
private:
int ResultA() { return 6; }
int ResultB() { return 5; }
};
class ThinkTrack2 {
friend class DeepThought;
private:
int ResultC() { ThinkTrack1 tt1; return tt1.ResultB() + 2; }
};
class DeepThought {
friend int DeepThoughtAnswers();
private:
int Answers() {
ThinkTrack1 tt1;
ThinkTrack2 tt2;
return tt1.ResultA() * tt2.ResultC();
}
int CreateWorld() {
return 7;
}
};
int DeepThoughtAnswers() { DeepThought dt; return dt.Answers(); }
}
,可以通过
调用#include "ControlledLib.h"
int i = ControlledLib::DeepThoughtAnswers();
实际答案由class DeepThought
的函数Answers()
提供,但是,为了使外部呼叫者只能访问一个Answers()
,我必须class DeepThought
函数私有,并创建一个全局函数DeepThoughtAnswers()
作为入口点,调用class DeepThought
来获得答案,然后class DeepThought
必须定义DeepThoughtAnswers()
}作为朋友函数。
它刚刚开始。由于class DeepThought
实际上会调用class ThinkTrack1
和class ThinkTrack2
,而class ThinkTrack2
会调用class ThinkTrack1
等等...为了让外部调用者无法访问所有这些,所有这些功能设置为私人,我必须定义很多朋友。最重要的是,所有这些都搞砸了内部访问控制!
什么是更好的方法呢?
答案 0 :(得分:1)
我建议您使用更多受保护的关键字并减少朋友关键字的使用,并再次重新设计界面,因为它看起来很混乱。实现和接口的桥接设计模式将很好,您可以将实现隐藏为库并仅将接口分发为头文件。
答案 1 :(得分:1)
设计界面时,您可以选择一些选项。第一种是只定义一个导出一组函数的C接口。这些函数在内部调用您的类,这些类通过该层隐藏。
<ControlledLib.h>
extern "C" int DeepThoughAnswers();
</ControlledLib.h>
在源文件中,您具有此功能的实现:
<ControlledLib.cpp>
#include "DeepThought.h"
#include "ThinkTrack1.h"
#include "ThinkTrack2.h"
int DeepThoughAnswers()
{
DeepThought dt;
return dt.Answers();
}
</ControlledLib.cpp>
您在此来源中包含的文件然后使用不带friend
的可见性,并且您只发送生成的库和ControlledLib.h
文件。
另一种方法是使用C ++接口隐藏实现细节。接口来了:
<ControlledLib.h>
class ControlledLib
{
public:
virtual int DeepThoughAnswers() = 0;
};
</ControlledLib.h>
然后你有一个这个接口的实现,可能如下所示:
<MyControlledLib.h>
class MyControlledLib : public ControlledLib
{
public:
virtual int DeepThoughAnswers();
void someOtherFunction(); //<-- not visible to the 'outside'
};
</MyControlledLib.h>
此外,您添加了一个工厂,允许客户端实例化您的库。
<ControlledLib.h>
#include "ControlledLib.h"
class MyControlledLibFactory
{
public:
static MyControlledLib* create();
};
</MyControlledLib.h>
对于客户端,您只运送工厂和界面,其他一切都被隐藏。 到目前为止,您的界面仅使用原始类型,这意味着您不必导出任何其他类型。如果您想在界面中使用类,您也需要导出这些类。
<ControlledLib.h>
class ControlledLib
{
public:
virtual int DeepThoughAnswers() = 0;
virtual ComplexAnswer* DeepThoughAnswersAreComplex() = 0; //<-- ComplexAnswer header needs to be supplied too.
};
</ControlledLib.h>