Hello,
I'm trying to do something like this:
- There're Base class and Derived classes.
- Some Derived classes use multiple inheritance, from Base class and a pure virtual class called Interface. These classes are able of some functionality that ordinary Derived classes aren't.
Why doesn't it work to cast a enhanced Derived class as a Interface class, and invoke its methods??
The example below shows exactly what I mean:
Code:
int main(void)
{
Base *base = new Base();
Base *polymorph= new Derived();
Derived *derived = new Derived();
cout << " This block works as expected. No problem" << endl << endl;
base->methodBase();
polymorph->methodBase();
derived->methodBase();
derived->methodInterface();
cout << " The problem begins here" << endl << endl;
((Interface*)polymorph)->methodInterface(); // <--- Problem is here
((Derived*)polymorph)->methodInterface();
delete base;
delete derived;
delete polymorph;
return EXIT_SUCCESS;
}
((Interface*)polymorph)->methodInterface() does not call methodInterface(), but Derived destructor. Which, of course, makes program crash on the next line, as Derived object has been destroyed.
I need to cast to Interface, because in my real application I have a list of pointers to Base class, and when I find out that some object is indeed, inheriting from Interface, I can think of no other way to call to Interface methods, without casting to every particular enhanced Derived class.
I use GNU g++.
I don't know why the above code doesn't work.
You might think I come from Java, and you'll be right. I don't use Java anymore, since some years ago, but this is the way I would work on it, using interface classes.
I'm sure there must be another way to go in C++, but I usually like my code to be as much portable as possible, and tend to stay away from language too-much-specific features.
that example doesnt show what you mean because it can't be compiled.
Code:
#include <iostream>
using namespace std;
class Base
{
public:
void methodBase(){std::cout << "base method" << std::endl;}
};
class Interface
{
public:
void methodInterface(){std::cout << "interface method" << std::endl;}
};
class Derived : public Base, public Interface
{
};
int main(void)
{
Base *base = new Base();
Base *polymorph= new Derived();
Derived *derived = new Derived();
cout << " This block works as expected. No problem" << endl << endl;
base->methodBase();
polymorph->methodBase();
derived->methodBase();
derived->methodInterface();
cout << " The problem begins here" << endl << endl;
((Interface*)polymorph)->methodInterface(); // <--- Problem is here
((Derived*)polymorph)->methodInterface();
delete base;
delete derived;
delete polymorph;
return 0;
}
output:
Code:
This block works as expected. No problem
base method
base method
base method
interface method
The problem begins here
interface method
interface method
The difficulty is that you're trying to simply reinterpret the pointer. While this would usually work for single inheritance since the memory layout puts the base class first on most compilers, multiple inheritance is more complicated.
Rather than using the C-style cast, try using a dynamic_cast and see if that solves your problem.
You might think I come from Java, and you'll be right. I don't use Java anymore, since some years ago, but this is the way I would work on it, using interface classes.
I'm sure there must be another way to go in C++, but I usually like my code to be as much portable as possible, and tend to stay away from language too-much-specific features.
It's fine to use multiple inheritance of type in C++ too. But note that your code wouldn't have worked in Java either.
The difference is that in Java you would've got a better error message. In fact I think a Java compiler would've caught this error already at compile-time and said "cast between unrelated types" or something. And even if it hadn't a Java compiler would've put in code to check the downcast at runtime and provided a proper "bad cast" message. To get that in C++ you need to use one of the new casts, namely dynamic_cast.
Last edited by nuzzle; September 26th, 2009 at 10:40 AM.
Personally I avoid multiple inheritance whenever I can. It's rarely necessary if the design is good, particularly given the capabilities of templates.
In Java multiple inheritance (of type) is a way of life really. Having a Java background myself I can understand that the OP wants to continue using this programming style. It's how you realise the first rule of OO, namely: Program to an interface, not an implementation (page 18 in Design Patterns by Gamma and others).
Last edited by nuzzle; September 26th, 2009 at 11:59 AM.
That works perfectly, but it really doesn't do the job, because I need to manually add cast for every single derived class, and not just use a single call for any possible Derived class which implements Interface.
In Java multiple inheritance (of type) is a way of life really. Having a Java background myself I can understand that the OP wants to continue using this programming style. It's how you realise the first rule of OO, namely: Program to an interface, not an implementation (page 18 in Design Patterns by Gamma and others).
I'd say that's the first rule of abstraction in general, not just OO. In fact it's the reason I was so hesitant to embrace templates at first-----there's no interface equivalent, you just have to "know" what methods the instantiating class needs to support.
Concepts were supposed to fix that lack, but I guess we have to wait a while longer for real, language-level support on that front.
Why?
In Java you always know the type of any object at runtime, and I don't remember having problems with these things
Well, the reason would be that Base and Interface are unrelated and that can be established already at compiletime. But I cannot swear that this particular cast would've been disallowed in Java. I know there are special rules when interfaces are involved.
I don't have a Java compiler on my computer so I cannot check it easily and I don't feel motivated enougth to locate the proper section in the Java Language Specification so I drop the issue here if you don't mind.
Don't know if it has any drawback, but it seems to go just fine.
The drawback is the usual. Downcasts are not typesafe and generally should be avoided.
Concepts were supposed to fix that lack, but I guess we have to wait a while longer for real, language-level support on that front.
Yes, it's a pity for generics in C++ that concepts didn't make it. In Stepanov's book Elements of Programming, concepts play an important role but when the time comes to use them in real Template code they're just treated as comments.
I've located another source and that's Modern C++ Design by Alexandrescu. On page 7 he states that "This analysis suggests that a combination of templates and multiple inheritance could engender a very flexible device, appropriate for creating design elements".
That's what I wanted to hear from an authoritative source really. At this point I'm not ready to write off OO as crap as Stepanov suggests. But who knows, with concepts in place it's a different story I guess. It would be great if Boost would provide an implementation of concepts.
Last edited by nuzzle; September 27th, 2009 at 02:29 AM.
* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.