views:

105

answers:

4

Hi!

I'm new to generic class programming so maybe my question is silly - sorry for that. I'd like to know whether the following thing is possible and - if so, how to do it

I have a simple generic class Provider, which provides values of the generic type:

template <class A_Type> class Provider{
public:
A_Type getValue();
    void setSubProvider(ISubProvider* subProvider)
private:
A_Type m_value;
ISubProvider* m_subProvider;
};

The getValue function shall return m_value in case of m_subProvider is NULL. But if SubProvider is not Null, the value shall be calculated by the SubProvider class.

so subprovider must be of generic type too, but i create it as an abstract class without implementation:

template <class A_Type> class ISubProvider{
public:
virtual A_Type getValue() = 0;
};

now I want the actual implementations of ISubProvider to be nongeneric! for example I want to implement IntegerProvider which returns type Integer

class IntegerProvider : public ISubProvider{
   int getValue(){return 123;}
};

and maybe a StringProvider:

class StringProvider : public ISubProvider{
  string getValue(){return "asdf";}
};

now - how can I code the whole thing, such that i can use the

void setSubProvider(ISubProvider* subProvider)

function of class Provider only with a subprovider that corresponds to the generic type of Provider?

for example, if i instanciate a provider of type int:

Provider<int> myProvider = new Provider<int>();

then it shall be possible to call

myProvider.setSubProvider(new IntegerProvider());

but it must be impossible to call

myProvider.setSubProvider(new StringProvider());

I hope you understand my question and can tell me how to create that code properly :)

Thank you!

A: 

You need to derive from your ISubProvider in the following way

class IntegerProvider : public ISubProvider<int>
class StringProvider : public ISubProvider<string>

And so on

Also change you class declaration

template <class A_Type> class Provider{
public:
A_Type getValue();
    void setSubProvider(ISubProvider<A_Type>* subProvider)
private:
A_Type m_value;
ISubProvider<A_Type>* m_subProvider;
};
BostonLogan
+2  A: 

C++ has templates (class templates and function templates), not generics.

Given this declaration:

template <class A_Type> class ISubProvider;

you can't do this:

class IntegerProvider : public ISubProvider{
    int getValue(){return 123;}
};

because ISubProvider is not a class, it's a class template.

You can though, do this.

class IntegerProvider : public ISubProvider<int> {
    int getValue(){return 123;}
};

I think that this is what you want to do, in any case.

This also won't work for the same reason.

template <class A_Type> class Provider {
public:
    A_Type getValue();
    void setSubProvider(ISubProvider* subProvider)
private:
    A_Type m_value;
    ISubProvider* m_subProvider;
};

You have to do something like this.

template <class A_Type> class Provider {
public:
    A_Type getValue();
    void setSubProvider(ISubProvider<A_Type>* subProvider);
private:
    A_Type m_value;
    ISubProvider<A_Type>* m_subProvider;
};

Now you have achieve what you wanted in that you must provide a pointer to an ISubProvider instantation for the same template type parameter as the Provider class template.

Note, however, that you haven't really gained anything by using a base class templated on type in this case.

Charles Bailey
A: 

If you drop the seperate idea of a provider/sub-provider and just create a single provider, your problem solves itself.

template <class A_Type> class Provider{
  typedef Provider< A_Type > my_type;

public:
  A_Type getValue();
  void setSubProvider(my_type* subProvider)
private:
  A_Type m_value;
  my_type* m_subProvider;
};
Evän Vrooksövich
A: 

Hello and thanks! this helped me already

anyway I still have a problem with this. If I do the following:

ISubProvider<class A_Type>* subProvider;
if (asdf=EINTEGER){
    IntegerProvider* ip = new IntegerProvider();
    subProvider = ip;
}
else{
    stringProvider* sp = new StringProvider();
    subProvider = sp;
}

then I get the following compilation error:

error C2440: '=': 'IntegerProvider *' cannot be converted to 'ISubProvider<A_Type> *'
Mat
Class is generated (instanciated) at compile time, so you can not expect subProvider be of one type or another type depending on some runtime information
BostonLogan
So then, how would i create an std::list<ISubProvider<class A_Type>* > and store an IntegerProvider as well as a StringProvider in it?
Mat