I'm trying to write a program where derived classes of ServiceWorker such as Firefighter can "confront" objects derived from class Incident (Fire, Injury, Robbery). The confrontation would return a boolean value of whether or not it succeeded. For example, a firefighter confronting a fire would be successful, but a firefighter confronting a robbery would not. ServiceWorker would track the number of confrontations and successful confrontations as well as have a confront method that will determine if the confrontation was successful.
I want to use traits to store what each derived class of ServiceWorker can confront in its class definition. However, in ServiceWorker the confront method creates the traits class, but I want to specialize it in its derived classes so each derived class only knows what it can confront.
class Incident { };
class Fire : Incident { };
class Robbery : Incident { };
class Injury : Incident { };
class ServiceWorker {
public:
ServiceWorker() : ratio(0), num_success(0), num_confronts(0) {
}
template <typename U>
struct can_confront {
static const bool result = false;
};
double successRatio() {
if(ratio)
return ratio;
else
throw;
}
template <typename T>
void confront(T incident) {
if(can_confront<T>::result)
num_success++;
num_confronts++;
ratio = num_success / num_confronts;
}
protected:
double ratio;
unsigned int num_success;
unsigned int num_confronts;
};
class Firefighter : public ServiceWorker {
public:
template <>
struct can_confront<Fire> {
static const bool result = true;
};
};
EDIT
So I managed to figure it out. I got rid of templates and made confront virtual, so making a derived class of ServiceWorker would only require redefining the virtual function and using ServiceWorker::confront. I also added confront_success() and calc_ratio() to make adding new ServiceWorkers easier. I made Firefighter::confront() take FirefighterIncident, which inherited from Incident. That way, adding new incidents for Firefighter would be easy since they'd only have to inherit from FirefigherIncident.
class Incident {};
class FirefighterIncident : public Incident {};
class Fire : public FirefighterIncident {};
class RescueCat : public FirefighterIncident {};
class ServiceWorker {
public:
ServiceWorker() : ratio(0), num_success(0), num_confronts(0) {
}
double successRatio() {
if(num_confronts != 0)
return ratio;
else {
std::cout << "Can't divide by zero in ratio!" << std::endl;
throw;
}
}
virtual void confront(const Incident&) {
num_confronts++;
calc_ratio();
}
protected:
double ratio;
unsigned int num_success;
unsigned int num_confronts;
void calc_ratio() {
ratio = num_success / (double) num_confronts;
}
void confront_success() {
num_success++;
num_confronts++;
calc_ratio();
}
};
class Firefighter : public ServiceWorker {
public:
using ServiceWorker::confront;
virtual bool confront(const FirefighterIncident&) { confront_success(); }
};
In my view, things get cleaner if you take advantage of std::true_type
and std::false_type
. In the base class,
class ServiceWorker {
public:
template <typename U>
struct can_confront: std::false_type { };
...
and in the derived class,
class Firefighter: public ServiceWorker {
public:
template<typename U>
struct can_confront: ServiceWorker::template can_confront<U> { };
...
Notice that I redefined can_confront
in the derived class (through inheritance), so that I can specialize it without specializing ServiceWorker::can_confront
. To do this, simply add
template<>
struct Firefighter::can_confront<Fire>: std::true_type { };
outside the class definition. The confront
template method will then work once the if
statement is replaced with
if(can_confront<T>::value)
However , remember that you're still left with the problem that confront
always uses ServiceWorker::can_confront<T>
, even when you call it through a Firefighter
object. An easy fix would be to copy the definition of confront
into each derived class.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.