ReferenceCountedObjectPtr and polymorphism question


#1

Hi Jules,

I’m using ReferenceCountedObjectPtr and ReferenceCountedObject extensively in my project. But have a question.

In normal C++ if class B inherits from class A, then if I have a pointer to an instance of B i can assign this to a pointer of class A.

Likewise, if i have a method as below, i can return a pointer of type B* as an A* since B inherits from A>
say
A* foo() {
B* pb = new B();
return pb;
}

What i would love to be able to do is this ( in the future )

ReferenceCountedObjectPtr foo() {
ReferenceCountedObjectPtr pb = new B();
return pb;
}

or :
ReferenceCountedObjectPtr pb = new B()
ReferenceCountedObjectPtr pA = pb;

Now CURRENTLY - the only way I can get statements such as the above to compile is something like this:

ReferenceCountedObjectPtr pA = pb->getObject();

In other words can we have something like ReferenceCountedObjectPtr be polymorphic. Is there something I can add - maybe a modified form of ReferenceCountedObjectPtr, which will do this for me ?
Is this something that could be added to JUCE in the future ?


#2

I must be missing something. In “normal C++”, how would you expect the = operator in the ReferenceCountedObjectPtr template class to look like?

In glancing at the classes, ReferenceCountedObject appears to be the ability to keep a reference count. So classes can inherent this ability by inheriting from this class.

In the early days of C++, lots of us did this with things like ‘list’ classes, the functionality to be part of a linked list, etc. And what we ran into was that we had to do oodles of casting to put the inherited functionality to work. All that casting defeats the purpose of a tightly cast language, so we would do things like make a special usage class for each type of object to encapsulate the casting. In other words, you would inherit ListObject, but then there would be a wrapper class for usage, AList, BList, etc. all derived from the List class (class that knew how to manipulate ListObject objects).

If RefereceCountedObjectPtr was not a template, but just a * to ReferenceCountedObject that did the basic work of incrementing/decrementing references, you would have the same type of situation. Every time you wanted to use the Ptr, you would have to cast it to your descendant object. All that casting would be a pain, so you would make a wrapper class to do it for you. That is, you wouldn’t just inherent ReferenceCountedObject, you would make your own pointer class that inherited from ReferenceCountedObjectPtr as well…

Enter Templates. Write the usage class once, and specific the target descendant at instantiation. Instead of creating a new SomethingList class every time I wanted to use the inherited functionality from ListObject, I could just go List, List. The template is automating all the casting in a robust way, so I don’t have to do it myself, over and over. In the first template experiments, it literally was translated into C style casting.

Think of ReferenceCountedObjectPtr as a non template, and look at your desired syntax if we think of templates as casting:

ReferenceCountedObjectPtr ptr1;
ReferenceCountedObjectPtr ptr2;

(A *)ptr1 = (B *)ptr2;

I’m expressly casting, so I’m telling the compiler exactly how to treat each object ptr. Templates exist primarily to automatically cast base object usage functionality to a specific descendant. This is a reference to a countable object of type A, this is a reference to a countable object of type B…

In that sense, the syntax that works makes perfect sense to me. 'I want to keep to references to this object, one expressly cast to the class it is, one expressly cast to a base class. The object is passed to both references (getObject). Creating a different type of reference directly from the first one just looks wrong to me. But, again, I could be missing something.


#3

no, and what exactly is wrong with using .GetObject()?


#4

is that “No” to the polymorphism in ANY kind of template, BOOST wise, or JUCE wise that could ever achieve this in the future or just “no” as in :

“No - the current way ReferenceCountedObjectPtr is written doesn’t support it” ( which of course we know already )


#5

The former. See Stroustrup’s “The Design and Evolution of C++” to understand why (Templates are covered in chapter 15).

Templates exist so that generic code can be reused with rigid typing. You are complaining that the templates you are declaring are enforcing rigid typing…

You keep throwing out the word polymorphic, but you really haven’t explained why expressly bypassing rigid typing incurred by choice (you created a template) using getObject() is objectionable to you. If you want free form polymorphism, just declare your ReferenceCountedObjectPtr templates to all use the ReferenceCountedObject class, then cast like crazy…

Seriously, if you want to understand Templates conceptually, spend a few hours implementing a simple linked list. Create a class for objects in your list, and another for managing the list itself. Once you are maintaining your next pointers, etc. as you add and remove, try to transfer this functionality to a list of something other than your original object. That is, inherit your list object class and then try to use the list to do something useful with the inherited class. If you don’t want to expressly cast everywhere in your code, which is an invitation for explosions, you’ll find yourself inheriting from the original List class into a specialized list class as well. The inheritance adds no functionality beyond putting casting in one place, so it represents bigger, slower code. Templates are meant to address this problem. Again, see Stroustrup’s explanation.


#6

Ok - here’s the score. You’ll probable think this is all madness - and believe me if I could start again I would have done things differently.

I am working on a source code translator that converts code from REALbasic ( very similar to VB.Net ) to C++ using JUCE.

REALbasic/REALStudio is a natively compiled cross-platform object-oriented language with its own framework and IDE. The language uses reference counting for memory management. Every instantiated class gets instantiated to a reference variable instead of a pointer. This can be passed around as pointers are
and behaves polymorhically, Ie i can assign a subclass reference directly to a reference variable which references the base class. And as one expects one can cast a base class reference to its subclass just as in C++. I basically want - if possible at all to replicate this behaviour as much as possible in its JUCE C++ form.
The reason why i’d prefer not to have to use getObject is for readability. As of a few days ago I actually modified the translator to insert the .getObject() code into the translated output, so this works ok. I’d just prefer to be able to have things look more terse and readable by not needing it.

I don’t care in the final analysis what kind of C++ object achieves this, class or template. i’m just asking if it can be done.

I don’t know how ( internally ) the REALbasic compiler and framework implement this - the RB low level framework and compiler etc is all written in C++ of course -
maybe they basically have to do something similar to the juice referenceptr template, but just include an equivalent of a framework "getObject()” in the final natively compiled binary output. Dunno.


#7

In fact, if I remember correctly, the real answer to the question of “why doesn’t it do the up-cast automatically?” is actually: “because VC6’s compiler broke when I tried to make it do that”.

Since I’m no longer bothered about VC6, I’ve updated the ReferenceCountedObjectPtr class to make it possible - your original example should now compile ok!


#8

Well, I think it’s a can of worms.
As soon as you enter multiple inheritance, you can’t cast anymore automagically or have the compiler do it for you.
(think of diamond inheritance for one).
The compiler will then require disambiguation, and since this is template code you can’t change, you’ll be struck to getObject.
If you never have diamond inheritance, then it’s ok, but if it might happen, you better set your translator to use getObject + cast everywhere.


#9

[quote=“X-Ryl669”]Well, I think it’s a can of worms.
[/quote]

I would agree. But I’m pretty old school. Interestingly, Stroustrup touched on this in a keynote speech just a few weeks ago:

http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Keynote-Bjarne-Stroustrup-Cpp11-Style

Edit: It appears that X-Rul669 is correct, wether or not it compiles depends on the ancestry of the classes, at least on VC2010.


#10

[quote=“jules”]In fact, if I remember correctly, the real answer to the question of “why doesn’t it do the up-cast automatically?” is actually: "because VC6’s compiler broke when I tried to make it do that”.

Since I’m no longer bothered about VC6, I’ve updated the ReferenceCountedObjectPtr class to make it possible - your original example should now compile ok![/quote]

Thanks Jules,

I’m only using Xcode 4 for the first release so I presume this will work with that too ?.


#11

Any modern c++ compiler should be fine.