1

I want to have an array that can hold elements of many classes data types, and each of these classes have a method called printInfo().

The way I can do that is by having a parent class called SomeParentClass that have a virtual method called printInfo(), and then I would make the classes data types that can be present in the array inherit from this class and override the printInfo() method, and then I can create an array of type SomeParentClass*.

Is there anything wrong with this approach?

I'm asking because I have read that a class should represent an entity (for example: BankAccount, Car, House, Student, etc.), but SomeParentClass doesn't represent an entity. I have also read that the relationship between a parent class and a child class is an "Is-A" relationship, but the classes that will inherit from SomeParentClass are not SomeParentClass (in the same way that a Car is a Vehicle for example).

6

The way I can do that is by having a parent class called SomeParentClass that have a virtual method called printInfo(), and then I would make the classes data types that can be present in the array inherit from this class and override the printInfo() method, and then I can create an array of type SomeParentClass*.

Is there anything wrong with this approach?

There's absolutely nothing wrong with that at all (although I'd very strongly recommend avoiding pointers and arrays, and instead choose something like std::deque with std::unique_ptr or std::shared_ptr so that you're not writing code which needs to deal with memory management).

From a language-agnostic 'OO' perspective, this is exactly the kind of scenario which inheritance is expected to be used with.

I'm asking because I have read that a class should represent an entity (for example: BankAccount, Car, House, Student, etc.), but SomeParentClass doesn't represent an entity. I have also read that the relationship between a parent class and a child class is an "Is-A" relationship, but the classes that will inherit from SomeParentClass are not SomeParentClass (in the same way that a Car is a Vehicle for example).

I can think of a few scenarios where this might be reasonable advice, although I can think of many more scenarios where this advice is misleading or wrong. There have been too many books, blogs and tutorials written over the years which attempt to explain OO in terms like this, and most of the time they're written by people whose own understanding of OO is misguided (At least from the point of view that it doesn't match up with Alan Kay's original definition of the term 'object oriented programming', which has nothing to do with entities).

Firstly, there's absolutely no requirement whatsoever that a class should represent a data entity. Sticking to this kind of mantra as a hard rule can very easily lead towards a very narrow and misguided way of thinking about code structure where any kind of behaviour which may happen to be related to a particular data entity belongs to that entity, resulting in heavily bloated classes containing dozens of methods which have little or no relationship to each other. This mindset frequently results in the "God Object" anti-pattern as described here: https://en.wikipedia.org/wiki/God_object

Class design is completely different to Entity Modelling - if you conflate 'entities' with 'classes' then you're also in danger of losing out on logical separation between different layers and modules in your code.

For example, in a layered/tiered architecture, you may have simple entity structures which contain no behaviour and are simply used to support CRUD operations to/from a persistence store. Typically, classes containing your core business logic should have no knowledge of persistence. If you follow the view that classes should be entities, then you can end up with 'business logic' classes which also contain a lot of methods unrelated to the business logic such as Read or Save, at which point the code loses any kind of clear structure or separation.

The key to object-oriented programming lies behind designing classes around logical separation and grouping of related behaviour (i.e. functions/methods).

That is to say, in many (but not all) circumstances, restricting your use of classes just to representing entities doesn't provide a useful structure to your code, and can sometimes be counter-productive.

If a class contains methods which have no relationship to each other and which serve completely unrelated requirements, then it's an indication that you've got a class which is doing too many things - but this is exactly what you're likely to end up with if you treat entities as classes. Most of the time the way to arrive at clean, modular code is to split unrelated methods across different classes which probably don't map neatly on to any entities in your problem domain.

On the other hand, Entity modelling is all about identifying and grouping logically related data attributes, and logical relationships between grouped data. In many cases, the criteria you might use when deciding whether to create a grouping of attributes into an entity (such as 3NF/BCNF) will be completely different to the criteria when deciding to create a grouping of behaviours into a class; for this reason, it's best to avoid blurring the lines between the concept of a data entity versus the concept of a class.

  • 3
    “Object-oriented programming is entirely unrelated to data” – WAT? One common viewpoint is that objects = data + behaviour. But I see your point that behaviour is more important. And regarding Kay's “original definition”, note while he later coined the term, OOP as a technique was discovered while developing the Simula language. Nygaard insists that the objects should literally represent a physical model, i.e. represent entities.Of course it's possible to argue that this definition is wrong and that best practices have changed since the 60s. – amon Jul 21 '18 at 11:49
  • 1
    @amon Good comments - That wasn't the best wording on my part. I hadn't been aware of exactly who originally pioneered the idea of objects representing real/physical entities, but ignoring the OO/not-OO issue, I have often found that code which attempts to follow that guideline seems to be doing so before actually taking any functional requirements into consideration. I don't think it's a useless guideline by any means, and there are places where it absolutely makes sense, but I find that way of thinking about 'OO' can be very restrictive and often unhelpful for managing complexity – Ben Cottrell Jul 24 '18 at 17:27
4

I suggest you make the array, of an interface type(abstract class in c++). Just declare an interface with the methods you want them to implement(define a contract) instead of making them inherit from a base class. That way you are tellling that classes implementing IPrintInterface satisfies that contract.

If you only want the items in array to have printInfo() method that’s will be my approach.

Inheritance is the strongest relation between classes, and your question suggests that the array classes don’t need such “strength”

  • 2
    The tags on the question say that it relates to C++. C++ doesn't distinguish between interface and implementation inheritance in the same way that modern languages like Java and C# do. – Jules Jul 21 '18 at 10:19
  • 5
    As C++ does not have a interface keyword, it might be worth mentioning that where languages like C# and Java use interfaces, C++ uses abstract base classes (and multiple inheritance). The fact that it is an interface should come from the naming of the abstract base class – Bart van Ingen Schenau Jul 21 '18 at 13:21
1

Since C++ doesn't have a base class of Object, such as Java and other languages, I think you are on the right track. Provided you give the parent class a suitable name which describes what your array is all about.

But I'm a bit puzzled over the fact that you need that kind of array. It makes me think there's something not right with the architecture or you're having a fight with the framework. Just a thought you have the answer to.

  • "But I'm a bit puzzled over the fact that you need that kind of array" What is wrong with an array that takes many data types (I think that other languages like PHP allows this by default)? – Christopher Jul 21 '18 at 6:59
  • @Christopher it doesn't have to be wrong, but I'm a bit curious that you need everything in a single array, instead of using other data structures, which you can access on demand. But I'm not aware of the current architecture, that's why I'm curious... – Benny Skogberg Jul 21 '18 at 7:03
  • 1
    Oh! I'm not working on an actual program, I'm just trying to learn about OOP. – Christopher Jul 21 '18 at 7:13
0

You do not (necessarily) have the is-a relationship and the types of the objects in your array may be diverse. This is flag for using interfaces rather than inheritance like Badulake suggests.

For types that do comply with the is-a relationship you could still implement this using a virtual method but the code traversing the array items would treat them as IPrintable objects (IPrintable would be a suitable name for your interface).

But your class framework may already have a virtual method ToString() built in, supported by every object. If it does, this could also be a good fit for this purpose because no matter how diverse the objects in your array, there will always be a ToString() you can override. In this case the is-a requirement is met: all objects are "stringifiables".

  • 2
    The question is tagged C++. That language doesn't support interfaces, and, by default, there isn't a class framework with a global superclass either. – Jules Jul 21 '18 at 10:22
  • @Jules He could be using C++.NET. And I do not know what libraries he is using, all his objects may have the same base for all I know. Furthermore he can use abstract base classes with multiple inheritance to the same effect, this is what interfaces mean in a C++ context. Interface does not necessarily refer to the keyword that does not exist in C++. – Martin Maat Jul 21 '18 at 12:04
0

...the classes that will inherit from SomeParentClass are not SomeParentClass(in the same way that a Car is a Vehicle for example).

Yes. But it is not wrong to have such inheritance relationship. You can see this in many libraries and frameworks. For example in Java the two popular list implementations ArrayList and LinkedList roughly descends from AbstractList.

The only thing to keep in mind is that we should not refer the concrete list instances (ArrayList or LinkedList) as AbstractList. We shall refer them as List for polymorphic concern or, ArrayList or LinkedList for data structural concern. Such superclasses provide convenience when we implement two or more similar classes and while referring those classes, such superclasses are mostly useless.

One more extreme example of this kind is empty implemented EventListeners. An event listener interface may have two or three abstract methods, like onClick(), onLongClick() and onDoubleClick() . The framework may also provide a default empty implementation for them. This implementation will be useful when we are interested in only one or two events.

0

Nothing wrong with this approach! Tho, you should ask if the printing is similar in most of the child classes, and do it in the base class.

class Print {                             // renamed for clarity.
    char const *    m_sInfo;
public:      Print(CS s) : m_sInfo(s)  {}
    virtual ~Print() {}
    virtual void print()     const     { cout << "Info: " << m_sInfo; } // universal
    virtual void printData() const = 0;   // abstract method
    virtual void printMisinformation() {} // called less often, thus using longer name
};
class Car : public Print {
    Engine       m_Engine;
public:         Car() : Print("Car"), m_Engine("V8") { }
    virtual    ~Car() {}
    virtual void printData() const     { m_Engine.print(); } // non-universal print
};

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.