John Paul Coder
John Paul Coder

Reputation: 313

How to make a common reusable function with different class types to reduce the code duplication using C++

I am invoking the below function from different classes and files like as shown below. And the implementation is almost similar. But it is initializing in the respective class constructor.

Can I create a common function for the below code for all the classes and then when invoking, based on the class can I initialize and return the object?

Below is the function with almost similar implementation for all the classes. And I have this similar implementation in around 10 places.

Could someone please suggest me the better approach to create a common reusable function?

1.

shared_ptr<CTestOneImpl> COneImpl::createTestObject(const string& f_strSFID, short f_nID,
                                                        bool f_bIsVerified,
                                                        bool f_bIsProcessed)
{
shared_ptr<CTestOneImpl> l_pTestObj = nullptr;
l_pTestObj = make_shared<CTestOneImpl>(f_nID, f_strSFID,
                                                    f_bIsVerified, f_bIsProcessed,
                                                    this);
 return l_pTestObj;
}
shared_ptr<CTestTwoImpl> CTwoImpl :: createTestObject(string f_hStrSFID, long f_nID,
                                                          bool f_bIsVerified,
                                                          bool f_bIsProcessed)
{
shared_ptr<CTestTwoImpl> l_pTestObj = nullptr;
l_pTestObj = make_shared<CTestTwoImpl>(f_nID, f_hStrSFID, f_bIsVerified
                                                , f_bIsProcessed, this);
return l_pTestObj;
}
shared_ptr<CTestThreeImpl> CThreeImpl ::createTestObject(const string& f_strSFID,
                                                     const string& f_nID,
                                                     bool f_bIsVerified,
                                                     bool f_bIsProcessed)
{
shared_ptr<CTestThreeImpl> l_pTestObj = nullptr;
l_pTestObj = make_shared<CTestThreeImpl>(f_nID,
                                              f_strSFID,
                                              f_bIsVerified,
                                              f_bIsProcessed,
                                              this);
return l_pTestObj;
}

Updated code using templatized class based on the inputs:

.h file

#include <iostream>
#include <list>

template <typename RetType, typename Args1, typename Args2, typename Args3>
class CTestImpl
{
public:
    CTestImpl(std::string f_lCallIdentifier, bool f_bIsVerified,
         bool f_bIsProcessed);

private:
    std::shared_ptr<RetType>
    createTestObject(Args1&& f_strSFID, Args2&& f_bIsVerified, Args3&& f_bIsProcessed);

public:
    void handleEvents(const std::string& f_eCallEvent, const std::string& f_strSFID);
};

.Cpp file

#include "TestImpl.h"

template <typename RetType, typename Args1, typename Args2, typename Args3>
// error: C2976: 'CTestImpl': too few template arguments
std::shared_ptr<RetType> CTestImpl<RetType>::createTestObject(Args1&& f_strSFID, Args2&& f_bIsVerified, Args3&& f_bIsProcessed)
// error: C2244: 'CTestImpl::createTestObject': unable to match function definition to an existing declaration
{
    return std::make_shared<RetType>(std::forward<Args1>(f_strSFID),
                                              std::forward<Args1>(f_bIsVerified),
                                              std::forward<Args1>(f_bIsProcessed));
}

//error: C2955: 'CTestImpl': use of class template requires template argument list
void CTestImpl::handleEvents(const std::string& f_eCallEvent, const std::string& f_strSFID)
{
    // error: C2509: 'handleEvents': member function not declared in 'CTestImpl'
    shared_ptr<CTestImpl> l_hCallObj = nullptr;
    l_hCallObj = createTestObject(f_strSFID, true, false);
}

Upvotes: 0

Views: 98

Answers (2)

Josh A.
Josh A.

Reputation: 394

You don't provide quite enough information, so I'm going to make some assumptions.

Assumptions

  1. The constructors of all the classes have the same signature. All of your calls to make_shared pass the same variables so I assume this is the case.
  2. All of the classes have similar functionality. You state that the implementations are almost the same, so let's assume this is the case.
  3. You have some way to differentiate between the classes. This is the assumption that would be best helped by knowing more information about what you're doing (maybe post the headers of some of the classes). For the purposes of this example, let's assume you know, at runtime, that you will want to instantiate a 'TestOne', 'TestTwo', or 'TestThree' object. I'm sure people will explain that this isn't the best or most efficient idea, and they would be correct, but this is real life and there are deadlines to meet and these classes appear to be test classes anyway so this should be sufficient.

Solution Use polymorphism.

/**
 * This is an interface that all of your test classes will need to implement.
 */
class ITest {
public:
   ~virtual ITest() = default;
   virtual void CommonMethod(...) = 0;
};

class CTestOneImpl : public ITest {
   void CommonMethod(...) override;
};

Assuming you are setup like the above for all 3 (or however many) of your classes, you can now create a factory class that will make some people sad.

class TestObjectFactory {
   enum class TestType{
       TestOne,
       TestTwo, 
       TestThree
   };

   static std::shared_ptr<TestObject> MakeTestObject(TestType &t, ...) {
       switch(t) {
       case(TestOne): return std::make_shared<CTestOneImpl>(...);
       ....
       default: return nullptr;
       }
   }
};

So when you want a CTestOneImpl, you just call auto test_obj_ptr = TestObjectFactory::MakeTestObject(TestObjectFactory::TestType::TestOne, ...)

Hope this answers your question, if it doesn't please provide some more info.

Upvotes: 0

max66
max66

Reputation: 66230

Not sure to understand what do you exactly want... but... what about as follows?

template <typename RetType>
shared_ptr<RetType> BaseClass::createTestObject (std::string const & f_strSFID,
                                                 short f_nID,
                                                 bool f_bIsVerified,
                                                 bool f_bIsProcessed)
{ return std::make_shared<RetType>(f_nId, f_strSFID, f_bIsVerified, f_bIsProcessed, this); }

Or, maybe better, if you pass the argument to createTestObject() (this also) in the same order required by the RetType constructor

template <typename RetType, typename ... Args>
shared_ptr<RetType> BaseClass::createTestObject (Args && ...as)
{ return std::make_shared<RetType>(std::forward<Args>(as)...)); }

But, at this point, you can directly call std::make_shared().

Upvotes: 1

Related Questions