Changing the behavior of an object at runtime

How can I change the behavior of an object at runtime? (using C ++)

I will give a simple example. I have an Operator class that contains an operate method. Suppose it looks like this:

 double operate(double a, double b){ return 0.0; } 

The user will provide some input values โ€‹โ€‹for a and b , and choose which operation to perform to say that he can choose to calculate addition or multiplication. Given its input, all I am allowed to do is create an instance of Operator and call operate(a, b) , which is written exactly as I mentioned earlier.

Methods for calculating multiplication or additions will be implemented somewhere (I donโ€™t know where).

In conclusion, I have to change the behavior of my Operator object based on user input.

+4
source share
11 answers

The standard template for this is for the outer class to have a pointer to the implementation class.

 // derive multiple implementations from this: class Implementation { virtual ~Implementation() {} // probably essential! virtual void foo() = 0; }; class Switcheroo { Implementation *impl_; public: // constructor, destructor, copy constructor, assignment // must all be properly defined (any that you can't define, // make private) void foo() { impl_->foo(); } }; 

impl_ redirecting all Switcheroo member impl_ to impl_ , you get the opportunity to switch to another implementation whenever you need.

There are different names for this template: Pimpl (short for "private implementation"), Smart Reference (unlike Smart Pointer, due to member functions) and has something in common with Proxy and Bridge templates.

+9
source

I mention it only as trifles and cannot help recommending it anymore, but here we go ...

WARNING DANGER !!!

A dumb trick that I saw is called squeezing, I think, but this is only for the true stupid. Basically you change the pointer of a virtual table to another class, it works, but theoretically it can destroy the world or cause other undefined behavior :)

In any case, just use the dynamic class and kosher C ++ instead, but as an experiment, it looks fun ...

+6
source

The Coplien Envelope / Letter Pattern (in his compulsory book Advanced C ++ Programming Styles and Idioms) is a classic way to do this.

In short, an envelope and a letter are both subclasses of the abstract base class / interfcae, which defines an open interface for all subclasses.

An envelope holds (and hides the true type) of the letter.

Different letter classes have different implementations of the public interface of an abstract class.

The envelope has no real implementation; it just helps (delegates) in his Letter. It contains a pointer to an abstract base class and points to a specific instance of the Letter class. As the implementation changes, you must change the pointer type of the Letter subclass.

Since users only have a link to the envelope, this change is invisible to them, except that the behavior of the envelope changes.

Coplien examples are especially clean because they are the letters, not the envelope, that cause the change.

One example of the hierarchy of the Number classes. The abstract base announces certain operations on all numbers, for example, adding. The integer and complex are examples of specific subclasses.

Adding Integer and Integer leads to Integer, but adding Interget and Complex leads to the creation of a complex.

Here's what the envelope to add looks like:

 public class Number { Number* add( const Number* const n ) ; // abstract, deriveds override } public class Envelope : public Number { private Number* letter; ... Number* add( const Number& rhs) { // add a number to this // if letter and rhs are both Integers, letter->add returns an Integer // if letter is aa Complex, or rhs is, what comes back is a Complex // letter = letter->add( rhs ) ) ; return this; } } 

Now, in the client index, it never changes, and they never need to know what Envelop holds. Here's the client code:

 int main() { // makeInteger news up the Envelope, and returns a pointer to it Number* i = makeInteger( 1 ) ; // makeComplex is similar, both return Envelopes. Number* c = makeComplex( 1, 1 ) ; // add c to i i->add(c) ; // to this code, i is now, for all intents and purposes, a Complex! // even though i still points to the same Envelope, because // the envelope internally points to a Complex. } 

In his book, Coplien goes deeper โ€” you will notice that the add method requires multiple submissions of some form โ€” and adds syntactic sugar. But this is the essence of how you can get what is called "run-time polymorphism."

+3
source

You can achieve this through dynamic binding (polymorphism) ... but it all depends on what you are actually trying to achieve.

+2
source

You cannot change the behavior of arbitrary objects using any reasonable method, unless the object was intended to use the behavior of the โ€œplug-inโ€ using some technique (composition, callbacks, etc.).

(crazy ways can overwrite the process memory where the function code is located ...)

However, you can overwrite the behavior of an object that is in virtual methods by overwriting vtable (the Approach can be found in this article ) without overwriting memory on executable pages. But this is still not a very reasonable way to do this, and it carries several security risks.

The safest way is to change the behavior of objects that were intended to be modified by providing the appropriate hooks (callbacks, composition ...).

+2
source

Objects always have behavior defined by their class.

If you need a different behavior, you need a different class ...

+1
source

You can also consider the dynamic linking role template .. I am struggling with the same as you. I read about the Strategy template, but the role also seems to be a good solution ...

+1
source

There are many ways to do this proxying, pImpl idiom, polymorphism, all with pros and cons. The solution that is best for you will depend on what kind of problem you are trying to solve.

0
source

Many ways:

Try if first. You can always change the behavior using the if statement. Then you will probably find the "polymorphism" more accurate, but it depends on your task.

0
source

Create an abstract class by declaring methods whose behavior should be variable as virtual. Create specific classes that will implement virtual methods. There are many ways to achieve this using design patterns.

0
source

You can change the behavior of an object using dynamic binding . Design models such as Decorator , Strategy will actually help you implement the same.

0
source

All Articles