I have a question about virtual functions in C++. I have spent the last hour searching but I'm getting nowhere quickly and I was hoping that you could help.
I have a class that handles transmitting and receiving data. I would like the class to be as modular as possible and as such I would like to make an abstract/virtual method to handle the received messages.
Although I know I could create a new class and overwrite the virtual method, I don't really want to have to create a large array of new classes all implementing the method different ways. In Java you can use listeners and/or override abstract methods in the body of the code when declaring the object as can be seen in the example.
JTextField comp = new JTextField();
comp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//Handler Code
}
});
Is this possible in C++ or is there a better approach to this sort of problem?
Cheers and Many thanks in advance,
Chris.
Have look at this other SO post Does C++0x Support Anonymous Inner Classes as the question sounds similar.
Functors (function objects) or lambdas could be suitable alternatives.
In C++, you need to declare a new class:
class MyActionListener: public ActionListener
{
public:
void actionPerformed(ActionEvent evt) { ... code goes here ... }
};
The question has already been answered but I thought I'd throw this in for good measure. The SO discussion linked in the example is good but concentrates mostly on replicating the Java experience. Here's a more idiomatic C++ way of doing it:
struct EventArgs
{
int param1;
int param2;
};
class network_io
{
typedef std::function<void (EventArgs)> Event;
typedef std::vector<Event> EventList;
EventList Events;
public:
void AddEventHandler(Event evt)
{
Events.push_back(evt);
}
void Process()
{
int i,j;
i = j = 1;
std::for_each(std::begin(Events), std::end(Events), [&](Event& e)
{
EventArgs args;
args.param1 = ++i;
args.param2 = j++;
e(args);
});
}
};
int main()
{
network_io ni;
ni.AddEventHandler([](EventArgs& e)
{
std::cout << "Param1: " << e.param1 << " Param2: " << e.param2 << "\n";
});
ni.AddEventHandler([](EventArgs& e)
{
std::cout << "The Param1: " << e.param1 << " The Param2: " << e.param2 << "\n";
});
ni.Process();
}
Related
I am writing some classes in C++ to act as a personal small library and I encountered a problem.
Some of my objects make us of third-party libraries written in magnificent C style.
That means those libraries have functions like apiInit() and apiCleanup(), where the former must be called before any of the actual api functions and the latter must be called when you are not going to use them anymore.
What I want is to provide the classes that need a library with an access point to its functions ensuring apiInit() is called when the first needing class is created, or at least before any api function is used, and apiCleanup() is called when the last instance that uses the api is destroyed.
Keep in mind there are more than one class that makes use of a single library.
I could come with two solutions:
First, the obvious one, make the provider a singleton:
#include <iostream>
using namespace std;
class ContextProvider {
ContextProvider() {
cout << "Initializing API" << endl;
}
ContextProvider(ContextProvider const& rhs) = delete;
ContextProvider& operator=(ContextProvider const& rhs) = delete;
public:
~ContextProvider() {
cout << "Cleaning API" << endl;
}
static ContextProvider& getInstance() {
static ContextProvider instance;
return instance;
}
void useContext() {
cout << "Using API" << endl;
}
};
class ContextUser1 {
public:
ContextUser1() {
}
void doSomething() {
ContextProvider::getInstance().useContext();
}
};
class ContextUser2 {
public:
ContextUser2() {
}
void doSomethingElse() {
ContextProvider::getInstance().useContext();
}
};
The other one would be to keep a counter of context users, like so:
#include <iostream>
using namespace std;
class ContextProvider {
static unsigned int userCounter;
public:
ContextProvider() {
if (userCounter == 0)
cout << "Initializing API" << endl;
++userCounter;
}
~ContextProvider() {
--userCounter;
if (userCounter == 0)
cout << "Cleaning API" << endl;
}
void useContext() {
cout << "Using API" << endl;
}
};
unsigned int ContextProvider::userCounter = 0;
class ContextUser1 {
ContextProvider cp;
public:
ContextUser1() {
cp = ContextProvider();
}
void doSomething() {
cp.useContext();
}
};
class ContextUser2 {
ContextProvider cp;
public:
ContextUser2() {
cp = ContextProvider();
}
void doSomethingElse() {
cp.useContext();
}
};
int main() {
ContextUser1 cu11, cu12, cu13;
ContextUser2 cu21, cu22;
cu11.doSomething();
cu12.doSomething();
cu21.doSomethingElse();
cu22.doSomethingElse();
cu13.doSomething();
}
Both, when executed with the following main()
int main() {
ContextUser1 cu11, cu12, cu13;
ContextUser2 cu21, cu22;
cu11.doSomething();
cu12.doSomething();
cu21.doSomethingElse();
cu22.doSomethingElse();
cu13.doSomething();
}
yeld the expected result, that is:
Initializing API
Using API
Using API
Using API
Using API
Using API
Cleaning API
Now the obvious question is, which one is better, or which one should I use?
For example, some things that come to mind are...
Singleton method:
Advantages:
No need to store any counter.
No need to store any instance.
Disadvantages:
Syntaxis gets weird (ContextProvider::getInstance().use()).
It is a singleton, with all it's flaws.
Counter method:
Advantages:
The usage is straightfowrard.
The syntaxis is nice and clear (cp.use()).
Disadvantages:
Has to keep a counter of the number of users.
User classes have to store an instance of the ContextProvider class.
I mainly ask this question because I don't know which of these advantages/disadvantages weight more, if there are things I didn't account for, or maybe there is an obvious third method I couldn't come up with that is inherently better than those two, or, who knows.
Thank you for your time!
I'd use your second approach, with the following modifications:
class ContextUser1 {
std::shared_ptr<ContextProvider> cp;
public:
ContextUser1(const std::shared_ptr<ContextProvider>& cp)
: cp(cp) {
}
void doSomething() {
cp->useContext();
}
};
Making the dependency explicit makes your code better in terms of being testable. Also, using shared_ptr takes care of counting, so you don't even need to do this yourself.
I have a problem in hand which requires to make a very modular design for different algorithms. For example population based optimization algorithms like genetic algorithm, particle swarm algorithm etc. There are several variants of these algorithms, therefore I planned to make the smaller building blocks as an abstract class and let the specific building block to be plugged in.
For example lets say we have algo1 which can be divided in the following subroutines
algo1
loop
{
sub1 ()
sub2 ()
sub3 ()
}
For this I can create three interfaces which the implementation will override as per their implementation. Therefore
//Sub1Class, Sub2Class, Sub3Class are interfaces/abstract classes
class algo1
{
sub1Class *sub1Obj;
sub2Class *sub2Obj;
sub3Class *sub3Obj;
}
// constructor or setter method to set the implementation
algo1 (Sub1Class *myAlgo1Obj, Sub2Class myAlgo1Obj, Sub3Class myAlgo1Obj)
{
sub1Obj = myAlgo1Obj;
sub2Obj = myAlgo2Obj;
sub3Obj = myAlgo3Obj;
}
doAlgo1
{
loop
{
sub1Obj->algo ();
sub2Obj->algo ();
sub3Obj->algo ();
}
}
This can be done, but all the algorithms uses the attributes of the algo class and there are intermediate variables shared by the algorithms which I do not want to give a getter/setter.
My question is what are the techniques which can be used to manage the shared intermediate variables between the algorithms. I can pass it as the algo method implementation argument, but the number of intermediates and the types may change from one implementation to another. In that case will it be a good idea to create a separate class of temporary variable or make something like friend in cpp? Note that the intermediate results can be large vectors and matrices.
Please let me know if you need more information or clarification.
NOTE: I can possibly omit the variables shared between the algorithms by introducing locals and re-computation, but the algorithms are iterative and computation intensive involving large matrices therefore I want to make object creation and destruction as minimum as possible.
I can propose to use Inverse of Control container to solve your problem.
First you should create several abstract classes to keep it in the container:
class ISubroutineState {
public:
ISubroutineState() = default;
virtual int getVar1() const = 0;
virtual void setVar1(int v1) = 0;
};
class ISubroutineState1 : public ISubroutineState {
public:
virtual std::string getVar2() const = 0;
virtual void setVar2(std::string& v2) = 0;
};
The example of the subroutine state class implementation:
class SubState1 : public ISubroutineState1 {
int var1;
std::string var2;
public:
int getVar1() const {
return var1;
}
std::string getVar2() const {
return var2;
}
void setVar1(int v1) { var1 = v1; }
void setVar2(std::string& v) { var2 = v; }
};
The the IoC container (please note it can be accessed in any way allowed - i used just static pointer for simplicity):
class StateBroker
{
std::map<const char*, ISubroutineState*> *storage;
public:
StateBroker();
template <class S>
void StateBroker::bind(S* state) {
storage->emplace(typeid(S).name(), state);
}
template <class S>
S* StateBroker::get() const {
auto found = storage->find(typeid(S).name());
if (found == storage->end()) return NULL;
return (S*)found->second;
}
~StateBroker();
};
StateBroker* stateBroker;
Now you can implement any type of the subroutines:
class ISubroutine {
public:
virtual void Execute() = 0;
};
class Sub1Class : public ISubroutine {
public:
void Execute()
{
if (stateBroker == NULL)
{
std::cout << "Sub1 called" << std::endl;
}
else {
ISubroutineState1* ss1 = stateBroker->get<ISubroutineState1>();
std::cout << "Sub1 with state called" << std::endl;
ss1->setVar1(1);
ss1->setVar2(std::string("State is changed by Sub1Class"));
std::cout << *static_cast<SubState1*>(ss1) << std::endl;
}
}
};
class Sub2Class : public ISubroutine {
public:
void Execute()
{
if (stateBroker == NULL)
{
std::cout << "Sub2 called" << std::endl;
}
else {
ISubroutineState* ss1 = stateBroker->get<ISubroutineState>();
std::cout << "Sub2 with state called" << std::endl;
ss1->setVar1(2);
std::cout << *static_cast<SubState1*>(ss1) << std::endl;
}
}
};
class Sub3Class : public ISubroutine {
public:
void Execute()
{
if (stateBroker == NULL)
{
std::cout << "Sub3 called" << std::endl;
}
else {
ISubroutineState1* ss1 = stateBroker->get<ISubroutineState1>();
std::cout << "Sub3 with state called" << std::endl;
ss1->setVar1(3);
ss1->setVar2(std::string("State is changed by Sub3Class"));
std::cout << *static_cast<SubState1*>(ss1) << std::endl;
}
}
};
Also please note that subroutine' Execute() can request any type of subroutine state it requires to perform their tasks. It can even create additional state instances (to use in later stage of the algorithm, for example).
Now the main algorithm would look like this:
class Algo {
private:
Sub1Class* sub1;
Sub2Class* sub2;
Sub3Class* sub3;
public:
Algo(Sub1Class* s1, Sub2Class* s2, Sub3Class* s3) : sub1(s1), sub2(s2), sub3(s3){}
void Execute()
{
sub1->Execute();
sub2->Execute();
sub3->Execute();
}
};
... and it's usage (please note it can be used as stateless and as statefull depending on the fact the StateBroker is initialized or not)
Sub1Class s1;
Sub2Class s2;
Sub3Class s3;
std::cout << "Stateless algorithm" << std::endl;
Algo mainAlgo(&s1, &s2, &s3);
mainAlgo.Execute();
stateBroker = new StateBroker();
SubState1* state = new SubState1();
stateBroker->bind<ISubroutineState>(state);
stateBroker->bind<ISubroutineState1>(state);
std::cout << "Statefull algorithm" << std::endl;
Algo statefulAlgo(&s1, &s2, &s3);
statefulAlgo.Execute();
Please note that Algo class doesn't know anything about subroutine states, state broker, etc.; Sub2Class doesn't know about ISubroutineState1; and StateBroker doesn't care about state and subroutine implementation.
BTW, you can review the example project at https://github.com/ohnefuenfter/cppRestudy (VS2015)
I'm working on an irc bot as a way to help me learn c++ and I was wondering if it is possible to use a method as a variable like this:
//Irc.h
public:
void *onJoin(char* sender, char* channel);
/////
//Main.cpp
void join(char* sender, char* channel)
{
cout << sender << endl;
cout << channel << endl;
}
int main()
{
Irc irc(stuff);
irc.onJoin = join;
}
Yes, it is possible. These variables are called functions pointers. The can write it like this:
void onJoin( char* sender, char * channel );
int main(void)
{
void (*func)(char *,char *);
func = &onJoin;
func( "sender", "channel" );
}
Alternatively you can use std::function<> for that. The code would be the same except for the first line in main() which is replaced by
std::function<void(char*,char*)> func;
This is a bit more legible in my opinion. If you use this, then don't forget to add
#include <functional>
to the top of your file. Instead of using such variables in a function, you can also use them as member variables of any struct or class.
You need a pointer-to-function:
void* (*OnJoinFn)(char*, char*);
In your Irc class,
class Irc
{
public:
OnJoinFn onJoin;
};
This can be assigned as you are doing above:
int main()
{
Irc irc(stuff);
irc.onJoin = join;
}
But I wonder, if you are just learning C++, do you really need a pointer-to-function? pointers-to-function are certianly legal and valid, but an unusual entity and I would typically expect to use some other mechanism. As a start, I would suggest looking in to abstract base classes:
class IIrc
{
public:
virtual void* OnJoin(const char*, const char*) = 0; // pure virtual
virtual ~IIrc() {}; // Don't forget to implement a virtual destructor in any ABC
};
class MyIrc
:
public IIrc
{
public:
void* OnJoin(const char* sender, const char* channel*)
{
// YOUR CODE HERE
}
};
int main()
{
IIrc* irc = new MyIrc;
irc->OnJoin (...);
}
I've taken the liberty of introducing const correctness in OnJoin.
You should also consider not returning a void*, which bypasses most of C++'s type safety mechanisms, but a pointer to an actual object, or another interface.
Finally, using new (and delete, which is missing here, resulting in a memory leak) is poor practice. Instead, prefer to allocate things on the stack or, if you really need dynamic allocation, use a smart pointer.
Whilst this is possible, I would suggest that you're most likely doing something wrong if you need to do this. The TYPICAL C++ way to do "we need to do this in different ways in different circumstances" is to use inheritance:
in irc.h:
class ircBase
{
public:
...
virtual void onJoin(char *sender, char *channel) = 0;
};
in ircXX.h:
class ircXX: public ircBase
{
public:
...
virtual void onJoin(char *sender, char *channel)
{
cout << sender << endl;
cout << channel << endl;
}
};
in ircYY.h:
class ircYY: public ircBase
{
public:
...
virtual void onJoin(char *sender, char *channel)
{
... do something else ...
}
};
And then you create an object of the right kind for what you need.
What you're looking for is a function pointer:
class Irc
{
public:
void (*on_join)(char*, char*);
// ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^
};
void join(char*, char*);
int main()
{
Irc irc(stuff);
irc.on_join = join;
}
Alternatively, you can use std::function so that you can pass capturing/non-capturing lambdas:
#include <functional>
class Irc
{
public:
std::function<void (char*, char*)> on_join;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
};
int main()
{
Irc irc(stuff);
irc.on_join = [] (char* sender, char* channel)
{
std::cout << sender << std::endl;
std::cout << channel << std::endl;
};
}
I want to store functions with similar signature in a collection to do something like this:
f(vector<Order>& orders, vector<Function>& functions) {
foreach(process_orders in functions) process_orders(orders);
}
I thought of function pointers:
void GiveCoolOrdersToBob(Order);
void GiveStupidOrdersToJohn(Order);
typedef void (*Function)(Order);
vector<Function> functions;
functions.push_back(&GiveStupidOrdersToJohn);
functions.push_back(&GiveCoolOrdersToBob);
Or polymorphic function objects:
struct IOrderFunction {
virtual void operator()(Order) = 0;
}
struct GiveCoolOrdersToBob : IOrderFunction {
...
}
struct GiveStupidOrdersToJohn : IOrderFunction {
...
}
vector<IOrderFunction*> functions;
functions.push_back(new GiveStupidOrdersToJohn());
functions.push_back(new GiveCoolOrdersToBob());
Premise:
The design you propose will work, but using regular function pointers will limit you considerably in the kind of callbacks you can register, and although more powerful, the approach based on inheritance from a fixed interface is more verbose and requires more work for a client to define callbacks.
In this answer I will first show some examples of how to use std::function for this purpose. The examples will pretty much speak for themselves, showing how and why using std::function brings advantages as opposed to the kind of solutions you outlined.
However, a naive approach based on std::function will also have limitations of its own, which I am going to list. This is why I eventually suggest you to have a look at Boost.Signals2: it is a pretty powerful and easy-to-use library. I will address Boost.Signals2 at the end of this answer. Hopefully, understanding a simple design based on std::function first will make it easier for you to grasp the more complex aspects of signals and slots later on.
Solution based on std::function<>
Let's introduce a couple of simple classes and prepare the ground for some concrete examples. Here, an order is something which has an id and contains several items. Each item is described by a type (for simplicity, here it can be either a book a dvd), and a name:
#include <vector>
#include <memory>
#include <string>
struct item // A very simple data structure for modeling order items
{
enum type { book, dvd };
item(type t, std::string const& s) : itemType(t), name(s) { }
type itemType; // The type of the item
std::string name; // The name of the item
};
struct order // An order has an ID and contains a certain number of items
{
order(int id) : id(id) { }
int get_id() const { return id; }
std::vector<item> const& get_items() const { return items; }
void add_item(item::type t, std::string const& n)
{ items.emplace_back(t, n); }
private:
int id;
std::vector<item> items;
};
The heart of the solution I am going to outline is the following class order_repository, and its internal usage of std::function to hold callbacks registered by clients.
Callbacks can be registered through the register_callback() function, and (quite intuitively) unregistered through the unregister_callback() function by providing the cookie returned by registered_callback() upon registration:
The function than has a place_order() function for placing orders, and a process_order() function that triggers the processing of all orders. This will cause all of the registered handlers to be invoked sequentially. Each handler receives a reference to the same vector of placed orders:
#include <functional>
using order_ptr = std::shared_ptr<order>; // Just a useful type alias
class order_repository // Collects orders and registers processing callbacks
{
public:
typedef std::function<void(std::vector<order_ptr>&)> order_callback;
template<typename F>
size_t register_callback(F&& f)
{ return callbacks.push_back(std::forward<F>(f)); }
void place_order(order_ptr o)
{ orders.push_back(o); }
void process_all_orders()
{ for (auto const& cb : callbacks) { cb(orders); } }
private:
std::vector<order_callback> callbacks;
std::vector<order_ptr> orders;
};
The strength of this solution comes from the use of std::function to realize type erasure and allow encapsulating any kind of callable object.
The following helper function, which we will use to generate and place some orders, completes the set up (it simply creates four orders and adds a few items to each order):
void generate_and_place_orders(order_repository& r)
{
order_ptr o = std::make_shared<order>(42);
o->add_item(item::book, "TC++PL, 4th Edition");
r.place_order(o);
o = std::make_shared<order>(1729);
o->add_item(item::book, "TC++PL, 4th Edition");
o->add_item(item::book, "C++ Concurrency in Action");
r.place_order(o);
o = std::make_shared<order>(24);
o->add_item(item::dvd, "2001: A Space Odyssey");
r.place_order(o);
o = std::make_shared<order>(9271);
o->add_item(item::dvd, "The Big Lebowski");
o->add_item(item::book, "C++ Concurrency in Action");
o->add_item(item::book, "TC++PL, 4th Edition");
r.place_order(o);
}
Now let's see what kinds of callback we can provide. For starter, let's have a regular callback function that prints all of the orders:
void print_all_orders(std::vector<order_ptr>& orders)
{
std::cout << "Printing all the orders:\n=========================\n";
for (auto const& o : orders)
{
std::cout << "\torder #" << o->get_id() << ": " << std::endl;
int cnt = 0;
for (auto const& i : o->get_items())
{
std::cout << "\t\titem #" << ++cnt << ": ("
<< ((i.itemType == item::book) ? "book" : "dvd")
<< ", " << "\"" << i.name << "\")\n";
}
}
std::cout << "=========================\n\n";
}
And a simple program that uses it:
int main()
{
order_repository r;
generate_and_place_orders(r);
// Register a regular function as a callback...
r.register_callback(print_all_orders);
// Process the order! (Will invoke all the registered callbacks)
r.process_all_orders();
}
Here is the live example showing the output of this program.
Quite reasonably, you are not limited to registering regular functions only: any callable object can be registered as a callback, including a functor holding some state information. Let's rewrite the above function as a functor which can either print the same detailed list of orders as function print_all_orders() above, or a shorter summary that does not include order items:
struct print_all_orders
{
print_all_orders(bool detailed) : printDetails(detailed) { }
void operator () (std::vector<order_ptr>& orders)
{
std::cout << "Printing all the orders:\n=========================\n";
for (auto const& o : orders)
{
std::cout << "\torder #" << o->get_id();
if (printDetails)
{
std::cout << ": " << std::endl;
int cnt = 0;
for (auto const& i : o->get_items())
{
std::cout << "\t\titem #" << ++cnt << ": ("
<< ((i.itemType == item::book) ? "book" : "dvd")
<< ", " << "\"" << i.name << "\")\n";
}
}
else { std::cout << std::endl; }
}
std::cout << "=========================\n\n";
}
private:
bool printDetails;
};
Here is how this could be used in a small test program:
int main()
{
using namespace std::placeholders;
order_repository r;
generate_and_place_orders(r);
// Register one particular instance of our functor...
r.register_callback(print_all_orders(false));
// Register another instance of the same functor...
r.register_callback(print_all_orders(true));
r.process_all_orders();
}
And here is the corresponding output shown in this live example.
Thanks to the flexibility offered by std::function, we can also register the result of std::bind() as a callback. To demonstrate this with an example, let's introduce a further class person:
#include <iostream>
struct person
{
person(std::string n) : name(n) { }
void receive_order(order_ptr spOrder)
{ std::cout << name << " received order " << spOrder->get_id() << std::endl; }
private:
std::string name;
};
Class person has a member function receive_order(). Invoking receive_order() on a certain person object models the fact that a particular order has been delivered to that person.
We could use the class definition above to register a callback function that dispatches all the orders to one person (which can be determined at run-time!):
void give_all_orders_to(std::vector<order_ptr>& orders, person& p)
{
std::cout << "Dispatching orders:\n=========================\n";
for (auto const& o : orders) { p.receive_order(o); }
orders.clear();
std::cout << "=========================\n\n";
}
At this point we could write the following program, that register two callbacks: the same function for printing orders we have used before, and the above function for dispatching orders to a certain instance of Person. Here is how we do it:
int main()
{
using namespace std::placeholders;
order_repository r;
generate_and_place_orders(r);
person alice("alice");
r.register_callback(print_all_orders);
// Register the result of binding a function's argument...
r.register_callback(std::bind(give_all_orders_to, _1, std::ref(alice)));
r.process_all_orders();
}
The output of this program is shown in this live example.
And of course one could use lambdas as callbacks. The following program builds on the previous ones to demonstrate the usage of a lambda callback that dispatches small orders to one person, and large orders to another person:
int main()
{
order_repository r;
generate_and_place_orders(r);
person alice("alice");
person bob("bob");
r.register_callback(print_all_orders);
r.register_callback([&] (std::vector<order_ptr>& orders)
{
for (auto const& o : orders)
{
if (o->get_items().size() < 2) { bob.receive_order(o); }
else { alice.receive_order(o); }
}
orders.clear();
});
r.process_all_orders();
}
Once again, this live example shows the corresponding output.
Beyond std::function<> (Boost.Signals2)
The above design is relatively simple, quite flexible, and easy to use. However, there are many things it does not allow to do:
it does not allow to easily freeze and resume the dispatching of events to a particular callback;
it does not encapsulate sets of related callbacks into an event
class;
it does not allow grouping callbacks and ordering them;
it does not allow callbacks to return values;
it does not allow combining those return values.
All these feature, together with many others, are provided by full-fledged libraries such as Boost.Signals2, which you may want to have a look at. Being familiar with the above design, it will be easier for you to understand how it works.
For instance, this is how you define a signal and register two simple callbacks, and call them both by invoking the signal's call operator (from the linked documentation page):
struct Hello
{
void operator()() const
{
std::cout << "Hello";
}
};
struct World
{
void operator()() const
{
std::cout << ", World!" << std::endl;
}
};
int main()
{
boost::signals2::signal<void ()> sig;
sig.connect(Hello());
sig.connect(World());
sig();
}
As usual, here is a live example for the above program.
You might want to look into std::function, your vector would then look like this:
std::vector< std::function< void( Order ) > > functions;
But be aware that std::function has a small overhead. For the instances, drop the new:
function.push_back(GiveStupidOrdersToJohn());
Boost.Signal solves exactly your problem. You should have a look into that. Unless you have special requirements. In particular boost.signal and boost.function and/or std::function
use type erasure techniques. Thus, you are able to have a vector of callable things with a specified signature. It does not matter if your entities are plain C-functions (as you have in your example) or function-objects or member-functions in general. You can mix all of them.
a bit of a vague question but I am looking for pointers as to how can I generate String diff vectors in C++. The scenario is such that given a paragraph I want to store the various differences(Edit, cut copy paste etc.) it goes through in a draft mode to review Audit history.
Any hints in this regard will be really appreciated.
An idea using C++ polymorphism:
class Action
{
public:
virtual void revert(std::string& base) = 0;
};
class InsertAction : public Action
{
private:
int pos, len;
public:
InsertAction(int pos, std::string& base, const std::string& in) : len(in.size()), pos(pos)
{
base.insert(pos, in);
}
virtual void revert(std::string& base)
{
base.erase(pos,len);
}
};
int main()
{
std::string text("hello !");
std::cout << text << std::endl;
Action* action = new InsertAction(5, text, " world");
std::cout << text << std::endl;
action->revert(text);
std::cout << text << std::endl;
delete action;
}
You can then add and pop Actions from a LIFO queue as you want. It's a simple example, you could also try to link it more to a string instead of always passing at as a param, but that's up to your own design. I know it's not 'real' diffing, but I think this solution to be closer coupled to the problem then really storing general string differences.