Click here to Skip to main content
15,892,537 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
I'm currently in the process of writing a class to produce PDF files. As a part of the PDF specification there are a number of basic types - i.e INT, FLOAT, STRING, ARRAY, DICTIONARY.

Currently, I've defined an abstract base class - pdfObj, from which all of these other types inherit. So far, so good.

One of the features of the array object is that each element in the array may be any of the above objects - including an array itself.

When adding an object to the array I need to determine the correct object type before creating a copy of that object and adding the copy to the array. While the implementation I have works, I can't help but wonder if there isn't something I'm missing or approaching the wrong way. I've attached the code below:

Any/all assistance will be most appreciated.

C++
void pdfArray::addItem(const pdfObj *newItem)
{
    pdfObj *item;
    if (typeid(*newItem) == typeid(pdfInt))
        item = new pdfInt( (pdfInt&) *newItem);

    if (typeid(*newItem) == typeid(pdfFloat))
        item = new pdfFloat( (pdfFloat&) *newItem);

    if (typeid(*newItem) == typeid(pdfString))
        item = new pdfString( (pdfString&) *newItem);

    *item = *newItem;
    mArray->push_back(item);
}
Posted

Why not use different overloads of the addItem() method which accepts any of the types you have? Something like:
C++
void pdfArray::addItem(const pdfInt *newItem)
{
// ...
}
void pdfArray::addItem(const pdfFloat *newItem)
{
// ...
}
// etc.
 
Share this answer
 
Comments
enhzflep 7-Mar-12 14:07pm    
Ahhhh! Of course.
Looks like a much better implementation than mine. Thank-you :)
Just realized that there's a better way to go about this..

Function Templates

The only 'ugly' thing is that I have to implement the function body in the header file - I can't have the definition in a H file and the implementation in a CPP file (without resorting to including the cpp file in the header file) :mad:

Anyhow, the final function body is short and sweet - it avoids maintenance issues since I just need to ensure that any new type that the function needs to deal with conforms to two standards:

1. The new object must be derived from pdfObj
2. The new object must have a copy constructor

The final code appears inside the class definition thusly:

C++
template <typename T> void addItem(const T *newItem)
 {
     pdfObj *item = new T(*newItem);
     mArray->push_back(item);
 }
 
Share this answer
 
Comments
Richard MacCutchan 8-Mar-12 4:01am    
A good solution.
enhzflep 8-Mar-12 10:10am    
Just to follow up, I found that in the destructor for the array class, that when I deleted each item in the vector of pointers to pdfObj, only the base class's destructor was being called - not the derived class's aswell, as would be expected (and needed, of course).

As a solution I found I could check the typeid, in a similar fashion to my first snippet. This then allowed me to cast each base class pointer in the array to a pointer of the correct type before deleting it. This seemed to invoke both the derived and the base class's constructors. But still it seemed like a crunchy kludge.

Of course, no way to use templates.

The solution? Ensure that the destructor for the base class was virtual.
Think I might have to go back and read up a little more a bit about the virtual beast..
Richard MacCutchan 8-Mar-12 10:34am    
Then you can explain it to me. ;)
enhzflep 8-Mar-12 23:34pm    
Okay, just had a very quick look about - 2 pages, each of them saying that you do indeed need to make the base destructor virtual if you want a derived class to be invoked when a derived class instance is deleted through a base class pointer. (phew! what a mouthful)

Though, wiki says that the behaviour is undefined if the virtual keyword is left-out. I guess it makes sense if you think about it - it's perfectly consistent with how you'd declare and use any other derived-class function you wanted invoked through a base-class pointer.

I guess since you don't explicitly call the destructor, I just didn't put 2 and 2 together.
Nelek 8-Mar-12 11:44am    
I know it is not the same and I am not sure if it will help you, but have you taken a look to http://www.codeproject.com/Articles/49/Smart-List-classes of Simon Hughes? Maybe it gives you an idea or another point of view about the template when calling the destructors.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900