I’m trying to make each instance of a class (named Caller here) have an instance of another class (Target). The point is that the second class has numerous children and I need to be able to have the Caller class switch among them at will. I have tried several ways, but not one gave me any desirable results. Current code:
class Target
{
public:
virtual void do_something()
{ log_message("NO!"); }
};
class TargetChild : public Target
{
public:
virtual void do_something()
{ log_message("YES!"); }
};
class Caller
{
private:
Target target;
public:
void call_target()
{ target.do_something(); }
void set_target(Target set_target)
{ target = set_target; }
};
int main( int argc, const char* argv[] )
{
TargetChild targetChild;
Caller caller;
caller.call_target();
caller.set_target(targetChild);
caller.call_target();
}
The wanted result in the log file is “NO! YES!” but instead it writes the NO! twice. I can’t really see what’s wrong with it.
You cannot change the type of an object in C++. You can only create, destroy, copy, and (in C++11) move data. In this case, you’ve copied the data from the subclass object to the base class object. This copied an empty subset of an empty subset. The problem you observed is called “slicing.”
Probably what you want is a member containing a function pointer that can be changed.
virtualgets you a function pointer but it can’t be changed. Trystd::tr1::function,boost::functionor C++11std::function.Or, if you really want to go the
virtualroute, use aTarget *pointer. Best to use a smart pointer class such asunique_ptr< Target >(again Boost/TR1/C++11) orstd::auto_ptr< Target >(old-fashioned C++03). You can also do it yourself withnewanddelete, but such code doesn’t really work as well, and is only suitable for a little educational tinkering.