在何处记录C++接口
Where to document interfaces in C++?
我有更多的Java背景,因此让我用Java的例子来说明。假设存在以下代码:
interface iFoo {
/* Do foo */
void foo();
/* Do bar */
void bar();
}
class A implements iFoo {
void foo() {};
void bar() {};
}
class B<iFoo> {
iFoo foo;
B() {
foo.foo();
foo.bar();
}
}
//somewhere in the code:
B b = new B<A>();
现在,如果我想实现一个可以用作 B 类型参数的类 C,我知道 C 必须实现 iFoo。因此,我去那里,按照合同设计惯例,所有必要的文档都将在那里(我需要实现哪些方法,那里有什么签名和内联文档。
在C++中,它看起来像这样(如果我错了,请纠正我):
class A {
public:
void foo();
void bar();
}
template<class T>
class B {
public:
T foo;
B() {
foo.foo();
foo.bar();
}
}
//somewhere in the code:
B *b = new B<A>();
记录 B 对 T 的期望的最佳位置在哪里?或者反过来,如果我有 A 和 B 并且想要实现一个作为类型参数传递给 B 的类 C,我如何找出 B 对 T 的期望?上面当然是一个非常微不足道的例子,想象一下更大更复杂的类。
在C++中,纯抽象接口类看起来像这样:
struct IFoo
{
virtual void foo() = 0;
virtual void bar() = 0;
virtual ~IFoo() {}
};
然后你像普通类一样继承它
class A : public IFoo
{
public:
void foo();
void bar();
};
我会说文档的一个好地方是定义类的头文件。库的用户将查看头文件以查看界面,这是她应该找到文档的位置,无论是整个类或模板还是公共成员。
整个类或模板以及每个公共成员都应该有详细说明目的、假设、先决条件等的文档。
例:
傅炯:
// The "Foo" template implements a gizmo according to Smith, Jones et al.
// A Foo<T> can be used as a drop-in replacement for the usual Zip<T>.
//
// The template parameter T must be a complete object type which is
// assignable and copyable.
template <typename T>
class Foo
{
public:
// Reflect the template parameters
using type = T;
using refence = T &;
// Constructs a Foo with a given state of being active, a given age
// and an identifier that represents its glurgh.
Foo(bool active, int age, char id);
// Perform the magic act of foo.
// It is safe to call this function multiple times concurrently.
// Returns the number of bars.
//
// Intended usage:
//
// Foo x(false, 10, 'a');
// registerGlobally(x);
// x.activate();
// return x.perform();
//
int perform();
private:
// ...
};
理想情况下,如果没有其他参考、手册或教程,用户应该能够通过查看标题来了解如何使用该类。如果你有纪律并并行维护一个适当的参考手册,你可以不用这些例子,但必要的信息(参数的含义和要求,返回值的意义)应该在那里。
当您从抽象基类公开继承时,这当然意味着基类已经包含所有接口文档,并且您不需要重复常规信息。但是,您仍然应该留下简短的评论,其中包含具体的覆盖,说明它们对您的实现具体作用。
如果希望模板参数满足某些约束(例如从某个基类派生),则可以通过使用类型特征、SFINAE 和模板元编程以编程方式强制执行。您仍应以人类可读的形式记录模板参数的要求,但在代码中强制实施此类约束是一种很好的卫生措施。
您可以使用虚拟方法执行与C++中的接口相同的操作,将=0
放在方法定义的末尾,您就拥有了有效的接口。(它实际上是一个基类,你必须从中派生,因为它本身不能实例化,并且在C++术语中被称为"抽象基类"。
但这给了你答案,没有什么能阻止你说 A 是基本接口,并将其用作"B 对 T 的期望"的定义。因此,如果 A 有 2 个方法,foo() 和 bar(),那么这就是它提供的,这也是从 A 派生的所有类也将具有的。
像Joachim建议的那样使用接口,但不幸的是,C++没有办法像在Java中那样强制执行它。因此,您必须将其记录为注释,例如在函数上方或类似的地方。
- C++核心准则 C35 对于接口类"A base class destructor should be either public and virtual, or protected and nonv
- Visual C++GC接口如何启用它以及要包含哪个库
- Windows.h与GLFW.h的接口
- 当字段可以为null时,如何使用C++接口在Avro中写入数据
- 提供与TMP和SFINAE的通用接口
- 为重写std::exception的库生成swig接口时出错
- 内联如何影响模块接口中的成员函数
- COM 接口 c# 封送数组数组
- 如何在 SCIP C++ 接口中获取 MILP 约束矩阵中的系数值
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- 如何绑定 C++ gRPC 客户端的网络接口
- 模板化接口 - 创建一个泛型模板类以返回任何容器
- 如何从实现接口的模板化类实例访问结构
- 带有进度表的 curl 多接口程序
- 设计帮助 - 为不同类型的消息处理通用接口的设计模式
- 我可以在具有一个标头和一个接口的 cpp 文件中有多个嵌入吗?
- 类接口,可以创建N个方法
- 类具有相同的接口,但参数的类型不同
- 如何与 Cheerp/js 中的 extern 变量接口?
- 如何使用现代 CMake 安装捆绑的接口依赖项?