tags:

views:

156

answers:

2

I was reading on the sealed keyword in C#. I cant remember the last time i inherit from a standard library. In c++ I remember inheriting an std interface that typedef a few types and used some of my parameters. But that is 1) Trivial 2) An interface

From the top of my head, i dont remember any class that i inherited that didnt have a virtual function expecting to be inherited. Can anyone tell me of a situation where you needed to inherit a non trivial class that wasnt an interface?

I might even say its a good rule to thumb not to inherit a class unless it has virtual functions. Is this a good rule of thumb?

NOTE: I use operator SomeClass& SomeClass() { return m_someClass; } in the case i need to pass my object as another class. It works well.

A: 

I would argue that the key concept of object-oriented programming is polymorphism. If inheriting from a particular class doesn't allow you to take advantage of polymorphism, then what is the point of inheriting? So if there are no methods to override, then do not subclass. You'd only be increasing the complexity of your code. If you want a lot of the same functionality, just wrap the existing class in your own.

Smashery
The key concept of OOD is that data and functionality are collected together to form objects that represent the subject they model. Polymorphism is an extension of that concept, nothing more.
Andrew Grant
The key concept of OOP is that no one can agree on what it is. As for polymorphism being an extension of that concept, I assume you it is possible to have polymorphism without "collecting data and functionality together to form objects."
Logan Capaldo
Nonetheless, the main purpose of inheritance is to facilitate polymorphism, not to represent real-world objects (just look at the Liskov Substitution Principle to see how using OOP to model real-world objects just doesn't work).
Smashery
@Smashery: How does the LSP imply "using OOP to model real-world objects just doesn't work"?
jpalecek
The typical example given with LSP is that of a square and a rectangle. In the real world, a square is a type of rectangle. However, if you subclass this, you violate the LSP (because rectangles can do things that squares can't: have sides of differing lengths)
Smashery
The problem I often see is people subclassing purely because it models a real-world object... and then they start having hacks to facilitate this inheritance.
Smashery
I think you got this wrong. It's not that you violate LSP by Square <: Rectangle, because everything that is true for a Rectangle holds for a Square too. The problem is, that people say they implement Square from the real world, but they actually don't.
jpalecek
In geometric terms, certainly, but not when you actually implement it. Something that is true for a rectangle: If I change its width, I have not changed its length. For a square, you cannot change one side without changing the other.
Smashery
... In the real world, Squares and Rectangles are just some Platos ideas, which means they are always immutable. However, when people implement them as classes, they implicitly assume variable semantics, which means they code some Infinite State Machines.
jpalecek
whereas Square <: Rectangle, ISM_Square is not <: ISM_Rectangle (as you noted). You just have to decide which side you like more-the functional, immutable, ideal world where inheritance is OK, parallelism is easy but memory management is hard, or the mutable, variable world which is the opposite.
jpalecek
A: 

It is actually used in C++, for all these not-is-a kinds of inheritance (eg. inheriting an implementation, mixins, boost::noncopyable, where you inherit from it and make your class noncopyable, boost::operators where you inherit from some class and it will add some operators to your class). Also, when doing metaprogramming with C++ types, inheriting from another type(s) is one of the simplest methods of composing types.

Another case where you inherit from a class that doesn't have virtual functions, but serves as "kind of" an interface, is static polymorphism (techniques like CRTP, where class ConcreteA : BaseA). They don't need the virtual functions, because everything is resolved at compile-time.

However, if you want to treat your class runtime-polymorphically, you should really make at least one method virtual, and that would be the destructor. There are exceptions, but rare.

Even when you have a polymorphic hierarchy, you sometimes derive from concrete classes. One example would be a SingleLineEdit deriving from TextEdit. However, this is a little dangerous, because it breaks encapsulation of the parent class (eg. its methods may expect some implementation details, and you must respect and preserve them in the subclass - which may be tricky, since they are implementation details that may change without notice in the next version etc.)

jpalecek