1

我有更多的 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 的期望?上面当然是一个非常琐碎的例子,想象一下更大更复杂的类。

4

4 回答 4

5

在 C++ 中,纯抽象接口类看起来像这样:

struct IFoo
{
    virtual void foo() = 0;
    virtual void bar() = 0;

    virtual ~IFoo() {}
};

然后你像普通类一样继承它

class A : public IFoo
{
public:
    void foo();
    void bar();
};
于 2013-10-16T08:23:42.980 回答
3

我想说文档的好地方是定义类的头文件。您的库的用户将查看头文件以查看界面,这就是她应该找到文档的地方,包括整个类或模板以及公共成员的文档。

整个类或模板以及每个公共成员都应该有详细说明目的、假设、先决条件等的文档。

例子:

富.h:

// 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 和模板元编程以编程方式强制执行。您仍应以人类可读的形式记录模板参数的要求,但在代码中强制执行此类约束是一种良好的卫生习惯。

于 2013-10-16T08:34:11.240 回答
0

您可以使用 Joachim 建议的接口,但不幸的是,在 C++ 中无法像在 Java 中那样强制执行它。因此,您必须将其记录为注释,例如在函数上方或类似的地方。

于 2013-10-16T08:36:03.547 回答
0

您可以通过使用虚拟方法来做与 C++ 中的接口相同的事情,将其放在=0方法定义的末尾,您就拥有了一个有效的接口。(它实际上是一个必须派生的基类,因为它本身不能实例化,在 C++ 术语中称为“抽象基类”。)。

但这给了您答案,没有什么能阻止您说 A 是基本接口并将其用作“B 对 T 的期望”的定义。因此,如果 A 有 2 个方法,foo() 和 bar(),那么这就是它所提供的,这也是从 A 派生的所有类也将拥有的。

于 2013-10-16T08:24:53.500 回答