Reputation: 13588
I have more of a Java background, thus let me illustrate with a Java example. Say the following code exists:
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>();
Now if I want to implement a class C that can be used as the type parameter for B, I know that C has to implement iFoo. Thus, I go there and by design-by-contract convention, all the necessary documentation will be there (which methods do I need to implement, what is there signature plus inline documentation.
In C++, it would look like this (correct me if I am wrong):
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>();
Where is the best place to document what B expects of T? Or the other way around, if I have A and B and want to implement a class C that is passed as type parameter to B, how do I find out what B expects of T? The above is of course a very trivial example, just imagine bigger and more complex classes.
Upvotes: 1
Views: 342
Reputation: 409196
In C++ a pure abstract interface class would look something like this:
struct IFoo
{
virtual void foo() = 0;
virtual void bar() = 0;
virtual ~IFoo() {}
};
Then you inherit it like a normal class
class A : public IFoo
{
public:
void foo();
void bar();
};
Upvotes: 5
Reputation: 477100
I'd say a great place for documentation is the header file which defines the class. A user of your library will look at the header file to see the interface, and that's where she should find the documentation, both for the class or template as a whole and for the public members.
Both the class or template as a whole and each public member should have documentation detailing purpose, assumptions, preconditions etc.
Example:
foo.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:
// ...
};
Ideally, absent other references, manuals or tutorials, a user should be able to work out how to use the class just from looking at the header. If you're disciplined and maintain a proper reference manual in parallel, you may be able to do without the examples, but the necessary information (meaning and requirements of parameters, meaning of return value) should be there.
When you inherit publicly from an abstract base class, this means of course that the base class contains all the interface documentation already, and you don't need to repeat the general information. However, you should still leave a short comment with the concrete overrides saying what they do specifically with respect to your implementation.
If you want template parameters to satisfy certain constraints, like being derived from a certain base class, you can enforce that programatically by using type traits, SFINAE and template metaprogramming. You should still document the requirements for template arguments in a human-readable form, but it is good hygiene to enforce such constraints in code.
Upvotes: 3
Reputation: 31952
You can use interfaces like Joachim suggests, but unfortunately, there is no way in C++ to enforce it, the way you would in Java. So you would have to document it as comments, say above the function or some such place.
Upvotes: 0
Reputation: 52679
You can do the same thing as interfaces in C++ by using virtual methods, put =0
at the end of the method definition and you have what is effectively an interface. (its actually a base class that you have to derive from as it cannot be instantiated itself and is called an 'abstract base class' in C++ terminology.).
But that gives you the answer, there's nothing stopping you from saying A is the base interface and using that as the definition of what 'B expects of T'. So if A has 2 methods, foo() and bar(), then that's what it supplies, and that's what all classes derived from A will have too.
Upvotes: 0