Good practice for developing ABC (abstract base class) in C ++

In java, we can define different interfaces, and then we can implement several interfaces for a particular 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 using multiple inheritance, although in some situations multilevel has its own advantage.

 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 ABC design, should I improve any other things to make it worthy of ABC?

Question2 Is it true that a good ABC should not contain member variables, and should instead be stored in subclasses?

Question3 As I pointed out in the comments, what if the ABC should contain too many pure functions? Is there a better way?

+3
source share
4 answers
  • Do not provide an implementation for pure virtual methods unless required.
  • Do not make your destructor pure virtual.
  • Do not protect the constructor. You cannot instantiate an abstract class.
  • It is better to hide the constructor and destructor implementation inside the source file so as not to contaminate other object files.
  • Make your interface not copied.

If it is an interface, it is better not to have any variables. Otherwise, it would be an abstract base class, not an interface.

Too many pure functions are fine if you cannot do this with less pure functions.

+9
source

In C ++, generally speaking, we should avoid using multiple inheritance

Like any other language function, you should use multiple inheritance wherever appropriate. Interfaces are generally considered appropriate using multiple inheritance (see, for example, COM).

The ABC constructor does not need protection - it cannot be created directly, because it is abstract.

The ABC destructor should not be declared as pure virtual (it must be declared as virtual, of course). You should not require derived classes to implement a user-declared constructor if they are not needed.

The interface should not have any state and, therefore, should not have any member variables, since the interface defines only what needs to be used, and not how to implement it.

ABC should never have too many member functions; he should have exactly as much as required. If there are too many of them, you should obviously remove those that are not used or not needed, or reorganize the interface into several more specific interfaces.

+9
source

Based on the ABC design, should I refine any other things to make it worthy of ABC?

You have a couple of syntax errors. For some reason, you are not allowed to enter a pure virtual function definition inside a class definition; and in any case, you almost certainly don't want to define them in ABC. Thus, ads will usually be:

 virtual void MethodOne(int /*i*/) = 0; // ";" not "{}" - just a declaration 

In fact, it makes no sense to make the destructor clean, although it should be virtual (or, in some cases, not virtual and secure), but it is safer to make it virtual).

 virtual ~ABC() {} // no "= 0" 

There is no need for a protected constructor - the fact that it is abstract already prevents the creation of an instance, except for the base class.

Is it true that a good ABC should not contain member variables, and instead variables should be stored in subclasses?

Usually yes. This gives a clear separation between interface and implementation.

As I pointed out in the comments, what if the ABC should contain too many pure functions? Is there a better way?

The interface should be as complex as it should be, and no more. There are only β€œtoo many” functions if some of them are not needed; in this case, get rid of them. If the interface looks too complex, perhaps it is trying to do a few things; in this case, you can break it into smaller interfaces, each of which has one purpose.

+4
source

First: why should we avoid multiple inheritance in C ++? I have never seen a fairly large application that has not used it extensively. Inheriting from multiple interfaces is a good example of where it is used.

Note that the Java interface does not work, as soon as you want to use contract programming, you are stuck using abstract classes and they do not allow multiple inheritance. However, in C ++, this is 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 can have a composite interface:

 class OneAndTwo : public One, public Two { }; class ImplementsOneAndTwo : public OneAndTwo { virtual void doFunctionOne( int i ); virtual double doFunctionTwo(); public: }; 

and inherits from him what ever makes the most sense.

This is a more or less standard idiom; in cases where it is possible, any preconditions or post-conditions in the interface (usually call inversion), virtual functions may be publicly available, but in general they will be closed, so that you can enforce the pre- and post-conditions.

Finally, note that in many cases (especially if the class represents a value), you simply implement it directly, without an interface. Unlike Java, you do not need a separate interface for implementing in another file from a class a definition of how C ++ works by default (with a class definition in the header, but the implementation code in the source file).

+3
source

All Articles