Virus721 Virus721 - 9 days ago 6
C++ Question

Calling the right free function from a base pointer/reference

Let a class hierarchy :

class Base { virtual ~Base() throw(); };

class DerivedA : public Base { };

class DerivedB : public Base { };


I would like to have some code specific to each of these derived classes. However that code also being specific to the application that makes use of this class hierarchy, I do not want to embbed this derived-class-specific code into these derived classes. To avoid doing so, I thought about writing free functions :

void DerivedASpecificWork( DerivedA da );

void DerivedBSpecificWork( DerivedB db );


However, when given an instance of a derived class through a reference/pointer to a Base, I do not have access to the actual type of the instance, and thus cannot call the proper Derived*SpecificWork() function.

I would like to know if there is nome kind of design pattern that would allow me to call a derived-class-specific function without knowing the actual type of the instance, i.e having the same mechanism as virtual functions provide, but without having these virtual functions that would require me to embbed application-specific code into that class hierarchy.

Actually, why I want to do that is to provide informations about an exception that occured within a natively implemented function called by a Lua script. Each exception carrying its own set of information, the way I want to represent the error within the script depends on the type of the exception. I could create a pure virtual method in the base class that would be implemented by derived classes, but this would require me to embbed Lua-related code into my exception hierarchy, which I do not want to do since the Lua is specific to one of the application using that exception hierarchy.

Also I cannot use C++11.

Thank you.

Answer

May be Brigde pattern can help you.

This pattern can be used when you want to avoid a permanent binding between an abstraction and it's implementation.

(I don't see your comment about your restriction in using c++11, but you can remove std::unique_ptr, std::move and override keyword)

class AppSpecificImp
{
public:
   virtual void DoWork() = 0;
};

class Base 
{ 
public:
   virtual ~Base() throw(); 

   virtual DoWork() = 0;
};

class DerivedA : public Base 
{ 
public:
   DerivedA(std::unique_ptr<AppSpecificImp> appImp)
      : imp(std::move(appImp))
   {
   }

   void DoWork() override
   {
       // DerivedA specific code 

       imp->DoWork();
   }

private:
   std::unique_ptr<AppSpecificImp> imp;
};

class DerivedB : public Base 
{ 
public:
   DerivedB(std::unique_ptr<AppSpecificImp> appImp)
      : imp(std::move(appImp))
   {
   }

   void DoWork() override
   {
       // DerivedB specific code 

       imp->DoWork();
   }

private:
   std::unique_ptr<AppSpecificImp> imp;
};

Edit to show Visitor pattern usage:

With visitor pattern you can do what you want but with more Effort.

class Visitor
{
public:
   virtual void VisitDerivedA(DerivedA* object) = 0;

   virtual void VisitDerivedB(DerivedB* object) = 0;
};

class Base
{
public:
   virtual void Visit(Visitor* visitor) = 0;
};

class DerivedA : public Base 
{ 
public:
   virtual void Visit(Visitor* visitor)
   {
       visitor->VisitDerivedA(this);
   }
};

class DerivedB : public Base 
{ 
public:
   virtual void Visit(Visitor* visitor)
   {
       visitor->VisitDerivedB(this);
   }
};

class AppSpecificVisitor : public Visitor
{
public:
   void VisitDerivedA(DerivedA* object)
   {
       // Do any work related to DerivedA class
   }

   void VisitDerivedB(DerivedB* object)
   {
       // Do any work related to DerivedB class
   }
}


int main()
{
    AppSpecificVisitor myVisitor;

    Base* myBase = // any class in your hierarchy

    myBase->Visit(&myVisitor);
}

As I said in comments with Visitor pattern you can add new functionally without changing the main hierarchy(Base->Derived types). You just define a new visitor implementation and write your logic for every class in main hierarchy. In your example you can pack app specific logic in an object and reference that in your derived objects that is an easier approach.

Comments