views:

197

answers:

6

Hello,

First of all I have to mention that I have read many C++ virtual questions in on stackoverflow. I have some knowledge how they work, but when I start the project and try to design something I never consider/use virtual or pure virtual implementations. Maybe it is because I am lack of knowledge how do they work or I don't know how to realize some stuff with them. I think it's bad because I don't use fully Object Oriented development.

Maybe someone can advise me how to get used to them?

+1  A: 

Check out abstract base classes and interfaces in Java or C# to get ideas on when pure virtuals are useful.

Virtual functions are pretty basic to OO. Theree are plenty of books out there to help you. Myself, I like Larman's Applying UML and Patterns.

Pontus Gagge
+2  A: 

Read the sections 19-25 of this excellent FAQ to get an idea about the how and when to use inheritance in C++.

Naveen
+1  A: 

but when I start the project and try to design something I never consider/use virtual or pure virtual implementations.

Here's something you can try:

  • Figure out the set of classes you use
  • Do you see some class hierarchies? A Circle is-a Shape sort of relationships?
  • Isolate behavior
  • Bubble up/down behavior to form interfaces (base classes) (Code to interfaces and not implementations)
  • Implement these as virtual functions
  • The responsibility of defining the exact semantics of the operation(s) rests with the sub-classes'
  • Create your sub-classes
  • Implement (override) the virtual functions

But don't force a hierarchy just for the sake of using them. An example from real code I have been working on recently:

class Codec {
public:
   virtual GUID Guid() { return GUID_NULL; }
};

class JpegEncoder : public Codec {
public:
   virtual GUID Guid() { return GUID_JpegEncoder; }
};

class PngDecoder : public Codec {
public:
   virtual GUID Guid() { return GUID_PngDecoder; }
};
dirkgently
A: 

You don't HAVE to use them but they have their advantages.

Generally they are used as an "interface" between 2 different types of funtionality that, code wise, aren't very related.

An example would be handling file loading. A simple file handling class would seem to be perfect. However at a later stage you are asked to shift all your files into a single packaged file while maintaining support for individual files for debug purposes. How do you handle loading here? Obviously things will be handled rather differently because suddenly you can't just open a file. Instead you need to be able to look up the files location and then seek to that location before loading, pretty much, as normal.

The obvious thing to do is implement an abstract base class. Perhaps call it BaseFile. The OpenFile function handling will differ dependent on whether you are using the PackageFile or the DiskFile class. So make that a pure virtual.

Then when you derive the PackageFile and DiskFile classes you provide the appropriate implementation for Opening a file.

You can then add something such as

#if !defined( DISK_FILE ) && defined ( _DEBUG )
#define DISK_FILE 1
#elif !defined( DISK_FILE )
#define DISK_FILE 0
#endif

#if DISK_FILE
typedef DiskFile File;
#else
typedef PackageFile File;
#endif

Now you would just use the "File" typedef to do all file handling. Equally if you don't pre-define DISK_FILE as 0 or 1 and debug is set it will automatically load from disk otherwise it will load from the Package file.

Of course such a construct still allows you to load from the Package file in debug simply by defining DISK_FILE to be 1 in advance and it also allows you to use disk access in a release build by setting DISK_FILE to 0.

Goz
@Goz: -1: You start off well enough talking about an abstract base class, but then you blow it by using the preprocessor! You should have either left out the explanation of selecting between Package and Disk, or gone on to using a factory so that very little code knows about either, but only knows about the abstract base class.
quamrana
+1  A: 

I don't have a ton of time ATM, but here is a simple example.

In my job I maintain and application which talks to various hardware devices. Of these devices, many motors are used for various purposes. Now, I don't know if you have done any development with motors and drives, but they are all a bit different, even if they claim to follow a standard like CANOpen. Anyway, you need to create some new code when you switch vendors, perhaps you motor or drive was end-of-life'd, etc. On top of that, this code has to maintain compatibility with older devices, and we also have various models of similar devices. So, all in all, you have to deal with many different motors and interfaces.

Now, in the code I use an abstract class, named "iMotor", which contains only pure virtual functions. In the implementation code only the iMotor class is referenced. I create a dll for different types of motors with different implementations, but they all implement the iMotor interface. So, all that I need to do to add/change a motor is create a new implementation and drop that dll in place of the old one. Because the code which uses these motor implementations deals only with the iMotor interface it never needs to change, only the implementation of how each motor does what it does needs to change.

Ed Swangren
+1  A: 

If you google for design patterns like the "strategy pattern" and "command pattern" you will find some good uses of interfaces and polymorphism. Besides that, design patterns are always very useful to know.

ssteidl