【发布时间】:2015-03-31 16:39:22
【问题描述】:
我在一个库中有多个类,这些类具有我希望对客户端代码隐藏的内部结构。 从客户端的角度来看,每个类都是从一个库类中查询的,并且仅用作不透明的指针.一个例子如下:
struct SomeSystem;
void doSomethingToSomeSystem(SomeSystem* system, Parameters params);
void doSomethingElseToSomeSystem(SomeSystem* system, Parameters params);
在实现方面,SomeSystem 有多个调用者不可见的成员。这一切都很好,但我不太喜欢笨拙的使用语法:
SomeSystem* system = lib->getSomeSystem();
doSomethingToSomeSystem(system, params);
doSomethingElseToSomeSystem(system, params);
另一种方法是这样的:
struct SomeSystem;
namespace somesystem {
void doSomething(SomeSystem* system, Parameters params);
void doSomethingElse(SomeSystem* system, Parameters params);
}
附使用代码:
SomeSystem* system = lib->getSomeSystem();
somesystem::doSomething(system, params);
somesystem::doSomethingElse(system, params);
我还可以使用名为doSomething 和doSomethingElse 的全局方法,如果另一种类型也定义了doSomething,则依赖于函数重载。但是,在这种情况下,很难在 IDE 中找到 SomeSystem 的所有“成员”。
我很想实际使用成员函数:
struct SomeSystem {
void doSomething(Parameters params);
void doSomethingElse(Parameters params);
};
附使用代码:
SomeSystem* system = lib->getSomeSystem();
system->doSomething(params);
system->doSomethingElse(params);
最后一个 sn-p 对我来说看起来不错,但 SomeSystem 不再是一个不透明的指针 - 它实际上定义了成员。我对此有点警惕。一个潜在的问题是单一定义规则。但是,类的“公共”定义和“私有”定义将只对不同的翻译单元可见。这里是否还隐藏着其他不好的东西?如果客户端代码尝试在堆栈上实例化 SomeSystem 或使用 new 它显然会使程序崩溃。但我愿意接受。也许我可以通过在公共接口中提供一个私有构造函数来解决这个问题。
另一种方法当然是用纯虚方法定义一个抽象类。 但是,如果不是绝对必要,我想避免这种开销。
编辑:
需要明确的是,我想知道客户端包含的公共标头包含与实现使用的类的不同定义(缺少一些成员)是否合法,因为客户端从不实例化类。
公共标头:
struct SomeSystem {
void doSomething(Parameters params);
void doSomethingElse(Parameters params);
};
私人标头:
struct SomeSystem {
Member member;
void doSomething(Parameters params);
void doSomethingElse(Parameters params);
};
私有源(包括私有标头):
void SomeSystem::doSomething(Parameters params) {
...
}
void SomeSystem::doSomethingElse(Parameters params) {
...
}
这在我测试时有效,但我不确定它是否以某种方式违反标准。这两个标题永远不会包含在同一个翻译单元中。
【问题讨论】:
-
是的,我很熟悉它,我宁愿避免它。它引入了额外的内存分配并使实现复杂化。
-
请注意,我特别喜欢语法糖,但不会使我的解决方案性能或复杂性更差。
-
您可以让类拥有接口,而不是使用接口超类/父级。这样,接口保持静态,您只需创建一个类来拥有该接口并在需要时使用它。
-
这需要虚函数,我想避免。
标签: c++ c++11 static-libraries one-definition-rule