-1

First, I know the answer is somewhere out there, but I've been searching all morning and didn't find it.

My question concerns what in Java looks like

abstract class AbstractWorker {
  public abstract int doIt();
}

class Thinker extends AbstractWorker {
  public int doIt() { return 42; }
}

class Milkmaid extends AbstractWorker {
  public int doIt() { return 1 + 2; }
}

class Worker {
  public int getWorkDone(AbstractWorker worker) {
    return worker.doIt();
  }
}

I think this should be possible in C++, too. But how do I implement this? My approach would look like

struct AbstractWorker {
  virtual int doIt() = 0;
};

struct Thinker : public AbstractWorker {
  int doIt() { return 42; }
};

struct Milkmaid : public AbstractWorker {
  int doIt() { return 1 + 2; }
};

struct Worker {
  int getWorkDone(AbstractWorker &worker) {
    return worker.doIt();
  }
};

What's wrong with this? Or how would you solve this?

Arne L.
  • 2,194
  • 19
  • 19
  • 1
    Milkmaid doesn't inherit from AbstractWorker but i don't see anything else wrong with it. – Detheroc Apr 30 '13 at 09:59
  • 1
    You need a virtual destructor for `AbstractWorker` and `MilkMaid` should inherit from `AbstractWorker`. Other than that, it looks fine. You might want to make the methods `const`, and pass a `const` reference to `getWorkDone`, but that is a separate issue. – juanchopanza Apr 30 '13 at 09:59
  • Why don't you use class instead of struct? And What type of error are you getting when compiling the C++ code? – mrz Apr 30 '13 at 10:00
  • 2
    @mrz there si no reason to use `class` instead of `struct` (other than personal preferences). – juanchopanza Apr 30 '13 at 10:01
  • I know struct is fine... I was just curios...also is int recommend to use structs as plain-old-data structures without any class-like features, and using classes as aggregate data structures with private data and member functions? – mrz Apr 30 '13 at 10:04
  • @mrz it really doesn't matter, it is just about conventions. Here, using `struct` saves typing `public` a few times... – juanchopanza Apr 30 '13 at 10:06
  • @juanchopanza IMHO since access in structs is by default public so as a general practice they are preferred for making interfaces (abstract classes with no implementation methods defined). Anything else should be a class just to match the terminology with OO paradigm. – Ali Apr 30 '13 at 10:29
  • 3
    I would ask you the same question. What's wrong with this? – Gorpik Apr 30 '13 at 11:36

2 Answers2

1

If there really is just one member function I'd implement this with functors and make getWorkDone a template.

struct Worker {
  template<typename F>
  auto getWorkDone(F f) -> decltype(f())
  { return f(); }
};

In case you really need type erasure over the different functors, there is std::function.

struct worker1 { int operator()() { return 23; } };
struct worker2 { int operator()() { return 5; } };

std::function<int()> func;
if(/* runtime stuff */ ) func = worker1();
else func = worker2();

Worker w; 
w.getWorkDone(std::ref(func));

Functors can also be used to maintain state:

template<typename Func>
struct Worker {
  Worker(Func f = Func()) : f_(f) {}

  auto getWorkDone() -> decltype(f_())
  { 
    // do something with the state in f_
    return f_(); 
  }

private:
  Func f_;
};
pmr
  • 58,701
  • 10
  • 113
  • 156
  • Yeah, if the scenario is really THAT easy, you could do so. Woukd be faster and probably easier. But I need the state of the Worker-object. – Arne L. Apr 30 '13 at 11:03
  • @ArneL. That doesn't seem to hard. Functors can have state. That's one of the main benefits over functions. You can also just write your own Concept. Something very similar to Functors but with some extra member functions for the state. – pmr Apr 30 '13 at 11:14
  • Maybe you can add an example with the state to your question. At it is my answer is correct, your question simply omits requirements ;-) – pmr Apr 30 '13 at 11:16
  • +1 for providing a nice alternative. By state I was referring to the subclasses of AbstractWorker. E.g. my actual problem involves random generator states at that point. – Arne L. Apr 30 '13 at 14:23
0

My question was a bit dubious. In fact I was a bit fast posting it. Anyways, I hope someone will find this useful.

Thanks for your responses. I polished my example and the following will actually compile and run:

#include <iostream>

struct AbstractWorker {
  virtual ~AbstractWorker() {};

  virtual int doIt() = 0;
};

struct Thinker : public AbstractWorker {
  int doIt() { return 42; }
};

struct Milkmaid : public AbstractWorker {
  int doIt() { return 1 + 2; }
};

struct Worker {
  int getWorkDone(AbstractWorker &worker) {
    return worker.doIt();
  }
};

int main() {
  Thinker work1;
  Milkmaid work2;
  Worker worker;

  std::cout << "result of work1: " << worker.getWorkDone(work1) << std::endl;
  std::cout << "result of work2: " << worker.getWorkDone(work2) << std::endl;

  return 0;
}
Arne L.
  • 2,194
  • 19
  • 19