1

I'm trying to build an object which is of a type which depends on input parameters. E.g. my object is called 'process' and at runtime an integer between 2 and 5 (inclusive) is entered and something a bit like this would happen:

if (input == 2) TwoJ   process;
if (input == 3) ThreeJ process;
if (input == 4) FourJ  process;
if (input == 5) FiveJ  process;

Obviously the above will not work because the object goes out of scope immediately. Is there a way to implement this nicely? Cheers

JMzance
  • 1,704
  • 4
  • 30
  • 49

3 Answers3

8

Use a factory function that returns a smart pointer to a base Process class and whose implementation is determined by an integer value supplied to the factory function (requires that all classes have a common base).

For example:

class Base_process
{
public:
    virtual ~Base_process() {}
    virtual void do_something() = 0;
};

class TwoJ : public Base_process
{
public:
    void do_something() {}
}
class ThreeJ : public Base_process
{
public:
    void do_something() {}
}

std::unique_ptr<Base_process> make_process(int a_type)
{
    if (a_type == 1) return std::unique_ptr<Base_process>(new TwoJ());
    if (a_type == 2) return std::unique_ptr<Base_process>(new ThreeJ());

    // Report invalid type or return an acceptable default if one exists.
    throw std::invalid_argument("Unknown type:" + std::to_string(a_type));
}
Community
  • 1
  • 1
hmjd
  • 120,187
  • 20
  • 207
  • 252
  • So my base class doesnt actually need to do anything neccessarily it just needs to be something from which all of the actual classes can be got at? – JMzance Jul 02 '13 at 10:52
  • @JackMedley, yes. It defines an interface that all dervied classes must implement. – hmjd Jul 02 '13 at 10:53
  • Ok I've build that and it seems to be ok with it! Great! One other related thing is: How do I access methods in the derived classes now? – JMzance Jul 02 '13 at 11:11
  • @JackMedley, the interface should declare all functions that the dervied classes implement. The client code should be written to use the interface, not a specific implementation of the interface, – hmjd Jul 02 '13 at 11:17
  • Ahh that would be the purpose of the 'virtual' tag! Ok I'll give that a shot. Thanks again – JMzance Jul 02 '13 at 11:18
  • Does a similar thing apply for class member variables? Or are they accesed without the needed for virtual declaration? – JMzance Jul 02 '13 at 11:21
  • **Possible refinement:** Since the argument to `make_process()` is `int _atype`, I'd prefer to use `switch (a_type) { case n: }` rather than `if (a_type == n) {}`. – DavidRR Jul 02 '13 at 12:07
  • @DavidRR, yes a `switch` would also be fine, or a table that maps an `int` to some creation function. – hmjd Jul 02 '13 at 12:41
2

A factory method of sorts

std::unique_ptr<ProcessType> CreateProcess(int input){ 
    if(input == 2) return std::unique_ptr<ProcessType>(new TwoJ());
    .....
}

This assumes, of course, that the various classes you use have a common base class, here ProcessType, and that you are satisfied with interacting with it via a base class pointer.

Karthik T
  • 31,456
  • 5
  • 68
  • 87
  • `ProcessType` should be returned by pointer (or better yet smart pointer) not by value otherwise you'll slice the object. – syam Jul 02 '13 at 10:37
0

you can but, you need 1 base class for those all e.g.

Base* process;

if (input == 2) process = new TwoJ();
if (input == 3) process = new ThreeJ();

then to access those class all you need is:

if (input == 2) (TwoJ*)process->someTwoJMethod();

or by using dynamic_cast:

TwoJ* p = dynamic_cast<TwoJ*>(process);
if(p != 0) {
   p->someTwoJMethod();
}

with this you own responsibility to delete your object once it's go out of scope. The previous answers are the best way in cpp using std::unique_ptr the object will get deleted automatically when the object go out of scope.

arifnpm
  • 357
  • 1
  • 7