views:

154

answers:

2

i'm just reading meyers "More Effective C++ 35 New Ways" - item 33, and he suggest there always to inherit from an abstract base class, and not a concrete.

one of the reason he claims, which i can't quite get , is that with inheriting from an abstract class, treating array polymorphically (item 3 in the book) is not a problem.

can someone suggest how is that ?

In addition i would like to hear if it's really always a good thing never to let the client instantiate a class which other derives from ? (meyers in his book is showing a problem with the assignment operator for example )

code example as requested:

CLASS BST {.... };

CLASS BlanacedBST:: public BST {....}

void printBSTArray(ostream& s, const BST array[],int Numelements) { for(int i=0;i < Numelements;i++) { s << array[i]; } }

BST BSTArray[10]; printBSTArray(BSTArray); // works fine

BlanacedBST bBSTArray[10]; printBSTArray(bBSTArray); // undefined behaviour (beacuse the subscript operator advances the pointer according to BST chunk size)

then, he addes that avoiding concreate class (BlanacedBST) inheriting from another concreat class(BST) usually avoids this problem - this i don't get how.

+2  A: 

While I think that avoiding inheritance from non-abstract classes is a good design guideline and something that should make you think twice about your design, I definitely do not think that it's in the category of 'never do this'.

I will say that classes designed to be inherited from that have data in them should probably be hiding their assignment operator because of the slicing issue.

I think there's a way to categorize classes that isn't often thought of, and I think that causes a lot of confusion. I think there are classes that are designed to be used by value, and classes that are designed to always be used by reference (meaning via a reference or a pointer or something like that).

In most object oriented languages user defined classes can only be used by reference, and there are a special class of 'primitive' types that can be used by value. One of C++'s big strengths is that you can create user defined classes that can be used by value. This can lead to some huge efficiency wins. In Java, for example, all of your points (to pick a random simple class) are heap allocated and need to be garbage collected, even though they're basically just two or three doubles stuck together with some nice 'final' support functions.

So classes that are designed to be used by reference should disable assignment and should seriously consider disabling copy construction and require people to use a 'make a copy of this' virtual function for that purpose. Notice that Java classes generally don't have anything like an assignment operator or standard copy constructor.

Classes that are designed to be used by value should generally not have virtual functions, though it may be very useful to have them be a part of an inheritance hierarchy. They can still be rather complex though because they can contain references to objects of classes designed to be used by reference.

If you need to treat a by reference class as being used by value you should use the handle/body design pattern or a smart pointer. The STL containers are all designed to be used on by value objects, so this is a fairly common problem.

Omnifarious
+1  A: 

Meyers does not say that you can create the array with no problems; he says that it will be more difficult for you to try to create it. The compiler will complain as soon as you try to initialise it, because you cannot create objects of the base class if it is abstract.

Gorpik
but the thing is not trying to create the base call , is using the base call as the function parameter , and sending the derived class as the argument... so i still can't see how using is as abstract helps
Idan
However, it is possible to fill an array of pointers to a base class.
Thomas Matthews