C++ ABCs good practice question

Started by
12 comments, last by Wavesonics 17 years, 2 months ago
So I'm using Abstract Base Classes as interfaces, and got a question for the OOP gurus out there. In my engine absolutely EVERYTHING inherits from a class called 'Element' which has certain function that allow it to function within my framework. But when I'm passing around objects of the Interface ABC the interface doesn't know about these functions. And I need to use these function. So should I put the 1 function I need in the interface even though that function as nothing to do with the purpose of the interface? Or maybe have a ABC of Element that all interface's inherit from so all Interfaces have those function that all classes have already defined?
==============================
A Developers Blog | Dark Rock Studios - My Site
Advertisement
Just discovered this doesn't even work.

Just because a parent class of a certain class implements a certain function, if the child class inherits from an interface which declares that function pure virtual it won't use the base classes implementation and will throw a compilation error.

So what should I do? reinterpret_cast when I need that function?
==============================
A Developers Blog | Dark Rock Studios - My Site
You might need to use the virtual keyword when inheriting the interface:

class Element{  public:    virtual void SomeFunction() = 0;};class MoreSpecificInterface : public virtual Element{  public:    virtual void SpecificFunction() = 0;};class AnotherInterface : public virtual Element{  public:    virtual void AnotherFunction() = 0;};class ConcreteClass : public virtual Element, public MoreSpecificInterface, public AnotherInterface{  public:    virtual void SomeFunction()    {    }    virtual void SpecificFunction()    {    }    virtual void AnotherFunction()    {    }};

The virtual keyword used when inheriting from Element says that there is only going to be one Element parent, and it will be shared among any classes that also virtually inherit the Element class. Otherwise, MoreSpecificInterface would have it's own Element parent, as would AnotherInterface, as well as ConcreteClass.
"We should have a great fewer disputes in the world if words were taken for what they are, the signs of our ideas only, and not for things themselves." - John Locke
Ok let me try to understand/clarify this:

class Element {    string getElementId() { return m_strElementId; }};class Interface {    virtual void someInterfaceFunc() = 0;};class SpecificSomething : public Element, public Interface {    void someInterfaceFunc() { // do something    }};


Now when I pass around an object of 'SpecificSomething' as the 'Interface' type I still need to be able to use the functions from my base class like 'string getElementId()'.

Soooo... Would what you are saying solve this problem? B/c from my understand it would not i don't think.
==============================
A Developers Blog | Dark Rock Studios - My Site
I'll leave the more in-depth answers to the gurus, but meanwhile I'll go out on a limb and say that:
Quote:In my engine absolutely EVERYTHING inherits from a class called 'Element' which has certain function that allow it to function within my framework.
This is probably might be a bad idea, and...
Quote:So should I put the 1 function I need in the interface even though that function as nothing to do with the purpose of the interface?
...no, you shouldn't.

You might find this article interesting. It's somewhat subjective and is focused more on generic components such as containers than on object hierarchies, but there are some points in the section titled 'Inheritance' that I think might be relevant.

Here is another interesting read that talks about some of the potential pitfalls of deep hierarchies.

There are some gotcha's as well that you have to watch out for when making use of inheritance and polymorphism. Furthermore, these sorts of errors can often go undetected and lead to undefined behavior (that's one of the reasons template programming gives me warm fuzzies - most of the errors happen at compile time ;). The thought of trying to manage a code base where every single class is part of the same hierarchy gives me the willies, but YMMV.

Again, I'm not a guru, but maybe the links I posted will at least give you some things to think about.

[Edited by - jyk on March 3, 2007 7:20:11 PM]
Well having a base class that implements functionality required to function with in the engine is, as I understand it, how most engines work. Wild Magic and Source (Half-Life 2) both do this.

But i'll check out those articles, thanks for the reply.
==============================
A Developers Blog | Dark Rock Studios - My Site
Quote:Original post by Wavesonics
Well having a base class that implements functionality required to function with in the engine is, as I understand it, how most engines work. Wild Magic and Source (Half-Life 2) both do this.
Well, I may have taken it too literally when you said 'everything' in your engine inherits from the Element class.

In any case, I'm sure that's a valid approach; I just wanted to point out that there are different ways of looking at the problem.

That said, my first statement that 'this is probably a bad idea' was probably too strong - I'll go back and edit it. However, I'll stand by my second statement regarding the addition of functions to the base class interface that are really only applicable for a particular derived class, as I think that definitely raises some red flags.
Yes I agree with what you said about adding the function to the interface. And infact, I ended up doing a dynamic_cast and it was able to find the base class just fine so i guess it's rather a non-issue, but again thank you for your posts!
==============================
A Developers Blog | Dark Rock Studios - My Site
Now the question is: why should a function that takes an Interface as a parameter expect to be able to use that Interface as an Element?

Case 1: There are Interfaces that are not Elements and the dynamic cast will not always work, which your code should be checking for to avoid dereferencing a null pointer.

Case 2: All Interfaces are Elements and the dynamic cast is completely redundant.

I think your engine falls under case 2.

If everything that implements one of your engine's interfaces should also implement element, you might want to consider making the interfaces themselves inherit from element. Now there's the issue of diamond inheritance...does your engine's design allow a single class to inherit from multiple interfaces? In that case, you'd also want to make your interfaces use virtual inheritance of the Element class (otherwise it doesn't matter).
Quote:
So should I put the 1 function I need in the interface even though that function as nothing to do with the purpose of the interface?


If every inheritor of an interface will have this function, I fail to see how that function has nothing to do with the interface.

If you want a logical disconnect:
class Element {    string getElementId() { return m_strElementId; }};class Interface: public Element {    virtual void someInterfaceFunc() = 0;};class SpecificSomething : public Interface {    void someInterfaceFunc() { // do something    }};


You can then reuse Element without Interface, and things tend to stay a little cleaner in the SpecificSomethings.

This topic is closed to new replies.

Advertisement