akslah
akslah

Reputation: 49

dynamic_cast to solve an implementation dilemma

This is something that has been frustrating me for over a week. I have gone through various threads on dynamic_casting on this website but I am still not sure what the best way to implement this is.

So I have a base class like this:

class baseClass
{
    public:

        class recordBase
        {
            public:
                virtual ~recordBase(){}
        };

        virtual ~baseClass() {};
        virtual bool Allocate( int size, 
                   recordBase *outRecord) = 0 ;
        virtual bool Free(recordBase *allocRecord) = 0;
} ;

This has two derived classes. A derived class A like so..

class DerivedA  : public baseClass
{
    public:

        class derivedRecordA : public baseClass::recordBase
        {
            public:
                inline ~derivedRecordA(){} ; 
                someClass *obj1 ;
         }
         bool Allocate(int size, 
                 baseClass::recordBase *outRecord);
         bool Free(baseClass::recordBase *allocRecord) ;
}

I have a similar derived class 'DerivedB' that has its own implementation of a dervied recordBase and Allocate and Free functions.

Now Finally I have a class C that uses the above baseClass.

class C
{
    public:
    baseClass *allocator ; 

    Allocate(int size) ; 
    Free(void) ; 
}

now here is my issue, based on some conditions class C either stores an allocator which is derivedA or stores one that is derivedB .

The allocate function for class C looks like this

C::Allocate(int size)
{
    //condition where DerivedA is needed       
    DerivedA::derivedRecordA recObj ;

    if(allocator->Allocate(size, &recObj)) 
    {
        return true;
    }
    else return false ; 
}

Now the problem is I am forced to use dynamic casting within the DerivedA::Allocate implementation like so:

DerivedA::Allocate(int size, baseClass:recordBase *outRecord)
{
    DerivedA::derivedRecordA *rec = dynamic_cast<  DerivedA::derivedRecordA *>(outRecord) ;

     //allocate mem and store info in 'rec'
     return true ;
}

How do I avoid using dynamic_casting here. Is there a cleaner solution to this problem ?

Upvotes: 0

Views: 92

Answers (2)

CB Bailey
CB Bailey

Reputation: 791401

There is a problem with your base class design which is why you are having implementation issues at the derived level.

If I have a pointer to a baseClass instance (whatever actual type it must be), then the implied contract of the Allocate method is that I can pass in a pointer to any kind of baseClass::recordBase and things should work.

If the derived classes override the function then they should not narrow the function requirements for users of the function. This would effectively mean that they are providing an override that doesn't satisfy the interface of the base class function. If they need to to this then they should provide a different function with a suitable interface.

Having said that, I would have expected an Allocate function to allocate a new object. In this case you can override and return a pointer to a specialization (this is known as a covariant return type). E.g., you can override:

virtual recordBase* Allocate(int size) = 0;

with

virtual derivedRecordA* Allocate(int size);

provided that size isn't supposed to be an array size and you are not trying to return a pointer to an array of derived objects which, again, would be problematic for users of the base class interface.

You really need to expand your question with what the contract and expected behaviour of your base class functions and there overrides are supposed to be to elicit better answers.

Upvotes: 1

Deduplicator
Deduplicator

Reputation: 45654

There is a cleaner solution, which is using a virtual function on baseRecord which is suitably overridden.

If that does not please, checking for typeid and using static_cast on success might be faster than dynamic_cast, even if it is bad coupling.

Upvotes: 0

Related Questions