简体   繁体   中英

what can I include in a c++ interface (abstract class)

I know that we have to at least add one pure virtual member function and its okay to add a static const and void returning methods,(a virtual destructor is a need too) but is there anything else we can add without having an error?

example:

// Base class
class Shape 
{
public:
   // pure virtual function providing interface framework.
   virtual int getArea() = 0;
   void setWidth(int w)
   {
      width = w;
   }
   void setHeight(int h)
   {
      height = h;
   }
protected:
   int width;
   int height;
};

A C++ interface is not a standard construct, it's just a class (or struct ) that the author has decided should be an interface. As such, it's down to convention as to what should and shouldn't go into it.

As a rule of thumb, the only things in an interface should be pure virtual functions . In that way, you are not supplying any implementation details, but just a description of the functionality that an object implementing that interface should have.

In C++, a class is abstract if at least one function is pure virtual. They will likely contain therefore data members and concrete functions in any way that suits the taste of the author.

You're jumbling together various concepts here.

An Abstract class is one in which at least one function is pure virtual, meaning it has a virtual function with the = 0 suffix indicating both that the class itself can't be instantiated, and that derived classes must specify an implementation of that function.

The only restriction the C++ language puts on an abstract class is that it can't be instantiated - it may still derive from bases and have static and non-static data and function members, and it may provide implementations for virtual functions - even pure virtual functions (base implementations of which could only be invoked by explicit calls, typically from a derived class's override of the same function - providing some default or additional behaviour).

Crucially, using an abstract base class as an "interface" implies you're forcing client code to use dynamic memory allocation and virtual dispatch. This means (shared) pointers everywhere and a particular set of programming practices and complexities that's common in such models, but may be uncomfortable or overwhelming for less experienced developers. An alternative is to use a very different style of "interface" class with value semantics employing the Pointer-to-Implementation (pImpl) idiom, which internalises some of the derived-class management - that tends to be more painful for the library implementer - more tedious little forwarding functions - but easier for the user.

One guideline to consider is Non-Virtual Interface (NVI) , which suggests that the public functions in a class should be non-virtual functions that call private virtual functions: that way, it may be possible to modify the base class to provide some pre- and post- code that's invoked when that function's called and before virtual dispatch to the derived class's implementation, eg retrofitting debugging, timing instrumentation, thread safety etc. to the base class and having it support the entire class hierarchy.

Everything that's in the base class that may need to be changed potentially necessitates recompiling all the client code that uses the base class (ie includes its header). In an enterprise environment, a change to the header for a low level library can force a hugely time-consuming recompile, and often as a library developer you only have the ability to distribute an update to your shared objects / dynamic libraries, but not control of when the client recompiles their dependent code to pick up changes from your header. In such situations, you preserve the most freedom to affect changes that are self-contained within your library if your base class didn't specify any details that could have been moved into the implementation class(es). As a guideline, you'd avoid any private members except perhaps those implementing a Non Virtual Interface as described above, and any associated with deliberate restrictions on the use of the class (eg making it "non-copyable").

Considering your Shape class, the most flexible base class with the same "interface" would be:

class Shape 
{
  public:
    virtual ~Shape(); // support dispatch to derived destructors

    // pure virtual function providing interface framework.
    int getArea() const;
    void setWidth(int w);
    void setHeight(int h);
  private:
    virtual void v_setWidth(int) = 0;
    virtual void v_setHeight(int) = 0;
};

The implementation file might start with:

void Shape::setWidth(int n) { v_setWidth(n); }
void Shape::setHeight(int n) { v_setHeight(n); }

Derived classes can add actual width and height members, or might choose to store say a centre and horizontal/vertical extent there-from, or a list of polygon points with no width or height members at all... you've allowed more variety in the derived classes without having the base class data members potentially hanging around unused. On the other hand, if 99% of derived classes do just want int width and height members, you could provide a distinct header with a class Shape_WH : public Shape { protected: int width, height; }; class Shape_WH : public Shape { protected: int width, height; }; to ease creation of such derived classes without forcing those details into client translation units or having them hanging around in the 1% of classes that don't want them....

[An answer specific to the example the OP has now posted].

Your class has shortcomings. In its current form it cannot really represent a circle (since you provide two degrees of freedom to calculate the area). You also can't easily represent irregular polygons.

What I think you should do is have an interface which is, conventionally, a class contaning virtual double getArea() const = 0; . Call it Shape . Then rename your class Rectangle which inherits from Shape .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM