条件成员函数
Posted
技术标签:
【中文标题】条件成员函数【英文标题】:Conditional Member Functions 【发布时间】:2011-08-06 17:52:50 【问题描述】:关于在 C++ 类中有条件地定义成员函数的建议是什么? (问题集中在限制 DLL 中某些类的外部暴露 - 特别是当这些类作为参数传入时)。显然这不是你想对数据成员做的事情,但函数应该没问题,不是吗?
例如:
class A
public:
void func1();
#ifdef _CONDITION_
void func2(B b);
#endif
;
已编辑: 添加公共修饰符以避免示例混淆。
【问题讨论】:
你能详细说明你为什么要这样做吗? #indef(预处理器)是编译前的东西,所以你不能用它来使成员函数出现在某些调用中而不是其他调用中。 当使用 C++ 中的共享库 (DLL) 时,您通常仍包含在库中编译的类的头文件。在这种情况下,我不希望使用 DLL 的软件看到这些头文件中引用的某些类。 oic;您正在创建不同风格的头文件,一种用于内部使用,另一种用于外部接口?听起来你的技术会很好。如果这与您的需求相似,我已经看到 #if 控制是否发出 __declspec(dllexport) 之类的东西的情况。 @seand 这样好吗?如果 dll 和程序看到类的不同定义,它们会构建不同的内部表示,并且类型虽然具有相同的名称,但不再匹配。如果是这样的话,听起来对我来说是一个糟糕的解决方案。 @ivella 你是对的!内部结构(vtables 等)将不正常。如果这是@Nicolas-s 最初的目标,也许最好只 dllexport 打算在外部可见的函数。 【参考方案1】:通常,如果您不想公开导出类的某些部分,那么您应该考虑不公开该类的选项,而是提供您的类继承自的抽象接口。
例如。
class AbstractExportedInterface
public:
virtual void do_stuff() = 0;
;
class HasStuffIDontWantToExport : public AbstractExportedInterface
public:
void do_stuff();
void do_other_stuff_that_i_dont_export();
;
那么您将假设您正在向 DLL 用户提供 HasStuffIDontWantToExport* 并且他们只有 AbstractExportedInterface 的标头。
编辑:对第一条评论的回应
如果您希望您的 DLL 客户端能够以某种方式使用某些类型(第 3 方或其他类型),但您不希望他们拥有对这些类型的完全访问权限,并且您没有灵活性使用直接继承层次结构来创建抽象接口。您也许可以使用 pimpl 模式为您希望客户端限制使用的每种类型创建代理接口?
例如。
class ExportedAbstractProxyObject
public:
virtual void do_stuff() = 0;
;
#include <3rdPartyType.h>
class ProxyObject
public:
void do_stuff() pimpl_.actually_do_stuff();
private:
3rdPartyType pimpl_;
;
class ExportedAbstractProxyOtherObject
public:
virtual void do_stuff_with_thing(ExportedAbstractProxyObject* thing) = 0;
;
class ProxyOtherObject
public:
void do_stuff_with_thing(ExportedAbstractProxyObject* thing) thing->do_stuff();
;
这样您就可以愉快地导出您喜欢的任何接口,并在您的 DLL 中完全隐藏实现和第 3 方类型。缺点是您显然必须创建所有这些代理对象接口。
【讨论】:
我喜欢继承方法,但它并不总是你可以控制的。例如,当正在创建的 DLL 链接到第三方创建的静态函数库时。【参考方案2】:您说您想阻止某些类的可见性,但您的示例仅隐藏了一个方法。
如果类不构成 DLL 的“公共”接口的一部分,则不需要发布标头。例如:
// foo.h
class Bar;
class Foo
private Bar* _bar;
...
这里的“Bar”是实现的一部分,所以不需要发送它的标题。如果 Bar 仅由 Foo 使用,您也可以在 Foo 的私有/受保护范围内定义它。
【讨论】:
不幸的是,在我的情况下,我更愿意将条件编译函数公开。 那么我会推荐 Vusak 的方法。使客户端依赖于接口或抽象类是控制反转 (IoC) 的基础,并允许您编写易于进行单元测试的高度模块化的代码。【参考方案3】:这类事情通常使用public
/protected
/private
声明,可能还有friend
s,而不是预处理器条件来完成。但是在我编写的一个程序中,将一组函数声明为私有或受保护(因为需要访问它们的独立函数的数量)更成问题,我在伪私有函数前面加上了前缀带有下划线的名称(以及解释原因的清晰 cmets),以使读者清楚这些函数并非用于一般用途。
【讨论】:
是的,但是使用下划线您仍然必须定义这些函数中使用的类型。因此必须向 DLL 的用户提供更多的头文件或前向声明。我真的只想提供 2 个头文件而不是 60 个。【参考方案4】:不完全确定您要问什么,但如果成员函数打算对类私有,请使用“private:”关键字将它们设为私有。
如果它们打算被其他类在该类所在的模块的上下文中使用,但您不希望外部实体知道它们,请将它们公开,但从“接口”派生类基类,并将该接口基类公开给外部实体。
【讨论】:
嗯,是的,但不幸的是,'private' 关键字不会阻止应用程序在编译时链接到 DLL,因为它需要成员函数参数的完整定义。还使用“private”关键字限制了该成员函数在数据包中的使用方式。以上是关于条件成员函数的主要内容,如果未能解决你的问题,请参考以下文章