DaClown
DaClown

Reputation: 4569

Specify a base classes template parameters while instantiating a derived class?

I have no idea if the title makes any sense but I can't find the right words to descibe my "problem" in one line. Anyway, here is my problem. There is an interface for a search:

template <typename InputType, typename ResultType> class Search {
public:
    virtual void search (InputType) = 0;
    virtual void getResult(ResultType&) = 0;

};

and several derived classes like:

template <typename InputType, typename ResultType> 
    class XMLSearch : public Search<InputType, ResultType> {
public:
    void search (InputType) { ... };
    void getResult(ResultType&) { ... };

};

The derived classes shall be used in the source code later on. I would like to hold a simple pointer to a Search without specifying the template parameters, then assign a new XMLSearch and thereby define the template parameters of Search and XMLSearch

Search *s = new XMLSearch<int, int>();

I found a way that works syntactically like what I'm trying to do, but it seems a bit odd to really use it:

template <typename T> class Derived;

class Base {
public:
 template <typename T>
 bool GetValue(T &value) {
  Derived<T> *castedThis=dynamic_cast<Derived<T>* >(this);
  if(castedThis)
   return castedThis->GetValue(value);
  return false;
 }
 virtual void Dummy() {}
};

template <typename T> class Derived : public Base {
public:
 Derived<T>() {
  mValue=17;
 }

 bool GetValue(T &value) {
  value=mValue;
  return true;
 }
 T mValue;
};

int main(int argc, char* argv[])
{
 Base *v=new Derived<int>;
 int i=0;
 if(!v->GetValue(i))
  std::cout<<"Wrong type int."<<std::endl;
 float f=0.0;
 if(!v->GetValue(f))
  std::cout<<"Wrong type float."<<std::endl;
 std::cout<<i<<std::endl<<f;
 char c;
 std::cin>>c; 
 return 0;
}

Is there a better way to accomplish this?

Upvotes: 2

Views: 1624

Answers (1)

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361672

Is there a better way to accomplish this?

Yes, that design is slightly better, since that's using static-dispatching while calling GetValue() (I'm assuming that dynamic_cast is typo, you actually wanted to type static_cast in Base::GetValue()). In that design, Base::GetValue() is not virtual, yet it is able to call Derived::GetValue() using pointer of type Base. This makes it slightly fast.

But even your way is not that bad. All you've to instantiate your class templates like this:

Search<int,int> *s = new XMLSearch<int, int>();

Your Search *s = new XMLSearch<int, int>() is wrong!


You can typedef your templates as follows:

typedef Search<int,int> iisearch;
typedef XMLSearch<int,int> iixmlsearch;

Then use them:

iisearch *s = new iixmlsearch();

This looks better, right?


Small Modification

You can make your class slightly better performance-wise. For that, write your Search class template as follows:

template <typename InputType, typename ResultType> class Search {
public:
    void search (InputType input) //it's not virtual anymore!
    {
        xmlsearch *_this = getXmlSearch();
        xmlsearch->search(input);
    }
    void getResult(ResultType& result) //it's not virtual anymore!
    {
        xmlsearch *_this = getXmlSearch();
        xmlsearch->getResult(result);
    }
private:
    typedef XMLSearch<InputType, ResultType> xmlsearch;
    xmlsearch* getXmlSearch()
    {
       static xmlsearch *_this= static_cast<xmlsearch* >(this);
       return _this;
    }
    
};

Now your base class is not abstract, as it doesn't define virtual functions. This design is slightly faster than your version!

Upvotes: 1

Related Questions