可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
In java, we can define different interfaces and then later we can implement multiple interface for a concrete class.
// Simulate Java Interface in C++
/*
interface IOne {
void MethodOne(int i);
.... more functions
}
interface ITwo {
double MethodTwo();
... more functions
}
class ABC implements IOne, ITwo {
// implement MethodOne and MethodTwo
}
*/
In C++, generally speaking, we should avoid the usage of multiple inheritance, although multi-inheritance does have its edge on some situations.
class ABC {
public:
virtual void MethodOne(int /*i*/) = 0 {}
virtual double MethodTwo() = 0 {}
virtual ~ABC() = 0 {}
protected:
ABC() {} // ONLY ABC or subclass can access it
};
Question1> Based on the design of ABC
, should I improve any other things in order to make it a decent ABC?
Question2> Is it true that a good ABC
should not contain member variables and instead variables should be kept in the subclasses?
Question3> As I indicated in the comments, what if ABC
has to contain too many pure functions? Is there a better way?
回答1:
- Do not provide an implementation for pure virtual methods unless it is necessary.
- Do not make your destructor pure virtual.
- Do not make your constructor protected. You cannot create an instance of an abstract class.
- Better hide an implementation of constructor and destructor inside a source file not to pollute other object files.
- Make your interface non-copyable.
If this is an interface, better do not have any variables there. Otherwise it would be an abstract base class and not an interface.
Too many pure functions is OK unless you can do it with less pure functions.
回答2:
In C++, generally speaking, we should avoid the usage of multiple inheritance
Like any other language feature, you should use multiple inheritance wherever it is appropriate. Interfaces are generally considered an appropriate use of multiple inheritance (see, for example, COM).
The constructor of ABC
needs not be protected--it cannot be constructed directly because it is abstract.
The ABC
destructor should not be declared as pure virtual (it should be declared as virtual, of course). You should not require derived classes to implement a user-declared constructor if they do not need one.
An interface should not have any state, and thus should not have any member variables, because an interface only defines how something is to be used, not how it is to be implemented.
ABC
should never have too many member functions; it should have exactly the number that are required. If there are too many, you should obviously remove the ones that are not used or not needed, or refactor the interface into several more specific interfaces.
回答3:
Based on the design of ABC, should I improve any other things in order to make it a decent ABC?
You've got a couple of syntax errors. For some reason, you're not allowed to put a definition of a pure virtual function inside a class definition; and in any case, you almost certainly don't want to define them in the ABC. So the declarations would usually be:
virtual void MethodOne(int /*i*/) = 0; // ";" not "{}" - just a declaration
There's not really any point in making the destructor pure, although it should be virtual (or, in some cases, non-virtual and protected - but it's safest to make it virtual).
virtual ~ABC() {} // no "= 0"
There's no need for the protected constructor - the fact that it is abstract already prevents instantiation except as a base class.
Is it true that a good ABC should not contain member variables and instead variables should be kept in the subclasses?
Usually, yes. That gives a clean separation between interface and implementation.
As I indicated in the comments, what if ABC has to contain too many pure functions? Is there a better way?
The interface should be as complex as it needs to be, and no more. There are only "too many" functions if some are unnecessary; in which case, get rid of them. If the interface looks too complicated, it may be trying to do more than one thing; in that case, you should be able to break it up into smaller interfaces, each with a single purpose.
回答4:
First: why should we avoid multiple inheritance in C++? I've never seen
a largish application which didn't use it extensively. Inheriting from
multiple interfaces is a good example of where it is used.
Note that Java's interface
is broken—as soon as you want to use
programming by contract, you're stuck with using abstract classes, and
they don't allow multiple inheritance. In C++, however, it's easy:
class One : boost::noncopyable
{
virtual void doFunctionOne( int i ) = 0;
public:
virtual ~One() {}
void functionOne( int i )
{
// assert pre-conditions...
doFunctionOne( i );
// assert post-conditions...
}
};
class Two : boost::noncopyable
{
virtual double doFunctionTwo() = 0;
public:
virtual ~Two() {}
double functionTwo()
{
// assert pre-conditions...
double results = doFunctionTwo();
// assert post-conditions...
return results;
}
};
class ImplementsOneAndTwo : public One, public Two
{
virtual void doFunctionOne( int i );
virtual double doFunctionTwo();
public:
};
Alternatively, you could have a compound interface:
class OneAndTwo : public One, public Two
{
};
class ImplementsOneAndTwo : public OneAndTwo
{
virtual void doFunctionOne( int i );
virtual double doFunctionTwo();
public:
};
and inherit from it, which ever makes the most sense.
This is the more or less standard idiom; in cases where there cannot
conceivably be any pre- or post-conditions in the interface (typically
call inversion), the virtual functions may be public, but in general,
they will be private, so that you can enforce the pre- and
post-conditions.
Finally, note that in a lot of cases (especially if the class
represents a value), you will just implement it directly, without the
interface. Unlike Java, you don't need a separate interface to maintain
the implementation in a different file from the class
definition—that's the way C++ works by default (with the class
definition in a header, but the implementation code in a source file).