It's seems as though I can't grasp the whole concept of polymorphism. There's only one thing I know about virtual members( they can be overloaded ).
I'm building a few custom exception classes for my memory allocation library. However, there's a few exception classes that're inherited from the base class EmptyBufferException.
Do I need to define a body for each member of EmptyBufferException?
Also, when my two other exception classes( OutOfRangeException, and InvalidBufferException ) inherit from EmptyBufferException, will I need to redefine the body of each inherited member of EmptyBufferException?
I've not been learning about inheritance for very long, so I'm still fresh off the shelf, so to speak.
class A{
public:
foo() { cout << "class A\n"; }
};
class B : public A {
public:
foo() { cout << "class B\n"; }
};
A a;
B b;
If we call foo() from 'a', the compiler will call A::foo(); if we call foo() from 'b', it will call B::foo().
But what if we do this:
A* c = new B;
It's perfectly well allowed, as A is a parent of B. But if we call c->foo(), the compiler sees 'c' as a pointer to A so it invokes A::foo().
As c is actually of type B, we want B::foo(). By making foo() a virtual function in A, we fix this problem. The correct function will be called (here, B::foo()) even if our object of type B is contained in a pointer to object of parent type A.
[edit]
Try using the above code as it is, and then change A to:
Thanks for the reply, Xander. It's more understandable now. So, would it be better if I only defined the prototypes for EmptyBufferException's members, and define them through the inherited classes? For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
class EmptyBufferException
{
// Other members...
virtualvoid vAssignErrorMessage( const std::string &strNewMessage ) = 0;
};
class OutOfRangeException : public EmptyBufferException
{
// Other members...
void vAssignErrorMessage( const std::string &strNewMessage );
};
// Definition of: OutOfRangeException::vAssignErrorMessage( )
void OutOfRangeException::vAssignErrorMessage( const std::string &strNewMessage )
{
// Code...
}
Okay. Firstly, I've looked at your first code again. You cannot have virtual constructors - they cause a compiler error. Think about it long enough and you'll realise that a virtual constructor doesn't make sense. (Virtual functions remove an ambiguity when calling a member function from a pointer or reference and you can't do that with a constructor.)
If you only define the prototypes, your class becomes an abstract class. This means you cannot instantiate it, and it's sole purpose is as a base class. You can, of course, still have pointers and references to to an object of this type: they will be pointing to some instance of a child class.
Note the '=0' at the end of one of your virtuals. This marks the function as pure virtual, i.e. it is not defined and only defined in derived classes. As soon as a class has one pure virtual member function, it is abstract.
If you mark a function as virtual, but not as pure virtual then you must provide a function body. Otherwise calls to the function will give a linker error just as with any undefined symbol.
*************** Important bit coming up ******************
In your original example, your functions appear mainly to be get/set functions. If a function is going to be implemented the same in parent and child class, then you need only define it in the parent class. No need for virtual or any of that stuff.
Virtual comes in to play when you want to change the behaviour in a derived class. (Hence the term polymorphism - poly = many, morph = shape.)
Do I need to define a body for each member of EmptyBufferException?
If you want the class to have the functionality, give it a body. If the class is merely a base for other classes which will implement the functionality, and this class will never be instantiated itself, there is no need for the body here.
will I need to redefine the body of each inherited member
You only need to redefine the body if you are going to change it. If you aren't going to redefine the body, don't change the function.
Finally, note that there is no need to make a function virtual if it won't be reimplemented differently in a child class.