I've recently come across a couple of situations that I think could be cleaned up with a different design, but I don't know of any patterns that would fit.
In all of these situations, I have a few classes that partially share an API. For example, a logger class:
struct ILogger { virtual void log(string msg) = 0; };
struct StdOutLogger : public ILogger {
void log(string msg) override; // Log to stdout
};
struct FileLogger : public ILogger {
void log(string msg) override; // Log to file
};
struct GuiLogger : public ILogger {
void log(string msg) override; // Log to GUI
void draw();
void clear();
};
or perhaps:
struct Graphic {
virtual void draw();
virtual void setPosition();
// etc.
};
struct AnimatedGraphic : public Graphic {
void draw() override;
void start();
void stop();
void setLooping(bool loop);
};
Now, depending on who owns these objects, I might have a container of references/pointers to a common interface:
class LogManager {
std::vector<std::unique_ptr<ILogger>> _loggers;
// ...
};
Or I might keep the types separated and choose at runtime which one to use:
// This is already starting to get messy
class SomethingWithGraphic {
std::unique_ptr<Graphic> _graphic;
std::unique_ptr<AnimatedGraphic> _animatedGraphic;
// ...
};
The first solution is fine until I need to start using the functionality that is not part of the common interface. The second solution allows me to choose the one I need, but it is error prone and requires ugly branches everywhere.
I've come up with a couple of alternative solutions, but I haven't found one that really feels right.
Keep one owning container, and create additional containers that point to the owned objects, but through a different interface. (Requires that the containers be kept in sync)
Add all functions to interface, but leave implementations empty for objects that don't need the extra functions. (Those functions don't really belong as part of that interface)
Store variants of all potential types. (Feels like a hack, requires visitors everywhere)
Using the logger example:
//// 1 ////
struct IDrawable {
virtual void draw() = 0;
virtual void clear() = 0;
};
std::vector<std::unique_ptr<ILogger>> _loggers;
std::vector<IDrawable*> _drawableLoggers;
//// 2 ////
struct ILogger {
virtual void log(string msg) = 0;
virtual void draw() {};
virtual void clear() {};
};
struct StdOutLogger : public ILogger {
void log(string msg) override; // Log to stdout
};
struct FileLogger : public ILogger {
void log(string msg) override; // Log to file
};
struct GuiLogger : public ILogger {
void log(string msg) override; // Log to GUI
void draw() override;
void clear() override;
};
//// 3 ////
std::vector<std::variant<StdOutLogger, FileLogger, GuiLogger>> _loggers;
#1 seems the most correct I think, but still not the greatest.
Does anyone know of any patterns or structures that could clean this up?
A viable approach: you can use a vector of pointers or references to your interface and implement the visitor pattern for all those cases in which you want to get out of one instance its actual type and call a method that isn't part of the common interface.
Here is a minimal, working example:
#include<iostream>
#include<memory>
#include<vector>
struct Visitor;
struct Interface {
virtual void method() = 0;
virtual void accept(Visitor &) = 0;
};
struct A: Interface {
void method() override { std::cout << "A::method" << std::endl; }
void f() { std::cout << "A::f" << std::endl; }
void accept(Visitor &) override;
};
struct B: Interface {
void method() override { std::cout << "B::method" << std::endl; }
void g() { std::cout << "B::g" << std::endl; }
void accept(Visitor &) override;
};
struct Visitor {
void visit(A &a) { a.f(); }
void visit(B &b) { b.g(); }
};
void A::accept(Visitor &v) { v.visit(*this); }
void B::accept(Visitor &v) { v.visit(*this); }
int main() {
std::vector<std::unique_ptr<Interface>> vec;
vec.push_back(std::make_unique<A>());
vec.push_back(std::make_unique<B>());
Visitor visitor;
for(auto &&i: vec) {
i->method();
i->accept(visitor);
}
}
Related
I come from a Delphi and C# background so I understand interfaces from their perspectives. I have been doing C++ for a few years and still learning interfaces from its perspective.
In my application I have a situation where I need classes that implement multiple interfaces (i.e. inherit multiple pure abstract classes) to indicate various behaviors that are supported by each class. This is not exactly ISP, but it is close enough that it is the same problem.
The behavior interfaces do not inherit from each other. There is no hierarchy.
Delphi and C# do this without breathing heavy but I am trying to figure out how this is done in C++. (Also, for now, I am limited to C++11.)
I have explored dynamic_pointer_cast, static_pointer_cast but they require an inheritance hierarchy.
I looked at reinterpret_pointer_cast, but it's not available in C++11.
I have tried using a root interface that my behavior interfaces inherit (similar to IUnknown in COM or IInterface in Delphi), creating an inheritance hierarchy, but then I run into the diamond problem.
I have seen some suggestions for adding methods to the base interface to return references to each behavior interface, but that's a kind of coupling I really don't want, since I may need to add other behaviors and classes that implement them later.
Here is some code, that I have not compiled, showing a simple example of what I am trying to do.
class IBase
{
public:
virtual void DoBaseStuff() = 0;
}
class IBehaviorA
{
public:
virtual void DoBehaviorA() = 0;
}
class IBehaviorB
{
public:
virtual void DoBehaviorB() = 0;
}
class Base : public IBase
{
public:
Base() {}
virtual ~Base() {}
virtual void DoBaseStuff() { /* ... */ }
}
class JustA : public IBase, public IBehaviorA
{
public:
JustA() {}
virtual ~JustA() {}
virtual void DoBaseStuff() { /* ... */ }
virtual void DoBehaviorA() { /* ... */ }
}
class JustB : public IBase, public IBehaviorB
{
public:
JustB() {}
virtual ~JustB() {}
virtual void DoBaseStuff() { /* ... */ }
virtual void DoBehaviorB() { /* ... */ }
}
class AandB : public IBase, public IBehaviorA, public IBehaviorB
{
public:
AandB() {}
virtual ~AandB() {}
virtual void DoBaseStuff() { /* ... */ }
virtual void DoBehaviorA() { /* ... */ }
virtual void DoBehaviorB() { /* ... */ }
}
void ProcessAllBehaviorA(std::vector<std::shared_ptr<IBase>> bases)
{
for (auto& base : bases)
{
std::shared_ptr<IBehaviorA> behaviorA
= SOME_KIND_OF_CAST<IBehaviorA>(base);
if (behaviorA != nullptr)
{
behaviorA->DoBehaviorA();
}
}
}
void main()
{
std::vector<std::shared_ptr<IBase>> bases;
bases.push_back(std::shared_ptr<IBase>(new Base()));
bases.push_back(std::shared_ptr<IBase>(new JustA()));
bases.push_back(std::shared_ptr<IBase>(new JustB()));
bases.push_back(std::shared_ptr<IBase>(new AandB()));
ProcessAllBehaviorA(bases);
}
I am trying to figure out what to do where the SOME_KIND_OF_CAST placeholder is in the ProcessAllBehaviorA method.
I am sure that I cannot be the first person to try to do this.
How do other people implement the Interface Segregation Principle (or similar patterns like mine) using smart pointers in C++?
I have explored dynamic_pointer_cast, static_pointer_cast but they require an inheritance hierarchy.
Your code does have an inheritance hierarchy, so std::dynamic_pointer_cast would work just fine! I have added some behavior to your code, and it works as expected.
#include <memory>
#include <vector>
#include <iostream>
class IBase
{
public:
virtual void DoBaseStuff() = 0;
};
class IBehaviorA
{
public:
virtual void DoBehaviorA() = 0;
};
class IBehaviorB
{
public:
virtual void DoBehaviorB() = 0;
};
class Base : public IBase
{
public:
Base() {}
virtual ~Base() {}
virtual void DoBaseStuff() { /* ... */ }
};
class JustA : public IBase, public IBehaviorA
{
public:
JustA() {}
virtual ~JustA() {}
virtual void DoBaseStuff() { /* ... */ }
virtual void DoBehaviorA() { std::cout << "I am just A!" << std::endl; }
};
class JustB : public IBase, public IBehaviorB
{
public:
JustB() {}
virtual ~JustB() {}
virtual void DoBaseStuff() { /* ... */ }
virtual void DoBehaviorB() { /* ... */ }
};
class AandB : public IBase, public IBehaviorA, public IBehaviorB
{
public:
AandB() {}
virtual ~AandB() {}
virtual void DoBaseStuff() { /* ... */ }
virtual void DoBehaviorA() { std::cout << "I am A and B" << std::endl; }
virtual void DoBehaviorB() { /* ... */ }
};
void ProcessAllBehaviorA(std::vector<std::shared_ptr<IBase>> bases)
{
for (auto& base : bases)
{
std::shared_ptr<IBehaviorA> behaviorA
= std::dynamic_pointer_cast<IBehaviorA>(base);
if (behaviorA != nullptr)
{
behaviorA->DoBehaviorA();
}
else {
std::cout << "Requested pointer does not implement A." << std::endl;
}
}
}
void main()
{
std::vector<std::shared_ptr<IBase>> bases;
bases.push_back(std::shared_ptr<IBase>(new Base()));
bases.push_back(std::shared_ptr<IBase>(new JustA()));
bases.push_back(std::shared_ptr<IBase>(new JustB()));
bases.push_back(std::shared_ptr<IBase>(new AandB()));
ProcessAllBehaviorA(bases);
}
Output:
Requested pointer does not implement A.
I am just A!
Requested pointer does not implement A.
I am A and B
By the way you missed the semicolons at the end of class definitions.
I am trying to implement Oppen's algorithm in C++.
The basic routines in this algorithm (print and scan) dispatch on a token type.
It seems natural to implement this dispatch using the visitor pattern.
The problem is: the routines are nested and the arguments to print() are enqueued in a stack during scan().
In order to avoid any memory problems, I would like to use smart pointers for the task.
So my implementation looks like this:
class Text;
class Line;
class Open;
class Close;
class Visitor {
/* Define virtual visit functions for concrete doc nodes:
*/
public:
virtual void visit(const Text&) = 0;
virtual void visit(const Line&) = 0;
virtual void visit(const Open&) = 0;
virtual void visit(const Close&) = 0;
};
class DocToken
{
protected:
explicit DocToken() {}
friend class Visitor;
public:
virtual void accept(Visitor * visitor) const = 0;
};
class Text : public DocToken {
public:
Text(std::string s) : text(s) {}
void accept(Visitor *visitor) const {
visitor -> visit (*this);
}
std::string text;
};
class Open : public DocToken { /* .. */ }
/* .. */
class Scan : public Visitor {
stream_t stream;
/* ... */
public:
void visit(const Open& x) {
/* ... */
stream.push_back(/* .. */ new Open() /* .. */);
/* ... */
}
void visit(const Text& x) {
/* ... */
stream.push_back(/* .. */ new Text(x) /* .. */);
/* ... */
}
/* .. */
}
As you can see, the Open token does not carry any data and can be constructed in place easily. The Text token does carry data (a std::string) and has to be copied in order to be pushed into the stream.
The stream needs to consist of pointers due to the common abstract base class of Open and Text.
Since on the outside, there is a smart pointer to that text token, I'd like to avoid the copying and simply use the existing smart pointer.
However, the accept method does not have access to that smart pointer.
Is there a way to implement a visitor pattern directly on smart-pointers? If not, how can I reduce the cost of copying the text token?
Technically, You can do this using std::enable_shared_from_this. (Note Pete Kirkham's excellent comment to the question, though - shared pointers indicate ownership. This is applicable to visitors that might outlive their originating documents, e.g., an ad-hoc dictionary builder, which might live after the document has been closed. Where no ownership is involved, raw pointers are the way to go.)
Below is a simplified version of your code illustrating this.
Say we start with the usual visitor-pattern forward declarations and base class definitions.
#include <memory>
#include <vector>
#include <iostream>
struct token;
struct visitor;
struct token {
virtual void accept(visitor &v) = 0;
};
struct text_token;
struct open_token;
When we define visitor, we make it accept std::shared_ptrs of the options:
struct visitor {
virtual void accept(std::shared_ptr<text_token> p) = 0;
virtual void accept(std::shared_ptr<open_token> p) = 0;
};
Now when we make concrete tokens, we:
subclass std::enable_shared_from_this
use shared_from_this to pass on the argument to accept
so the concrete tokens become:
struct text_token : public token, public std::enable_shared_from_this<text_token> {
virtual void accept(visitor &v) override {
std::shared_ptr<text_token> p{shared_from_this()};
v.accept(p);
}
};
struct open_token : public token, public std::enable_shared_from_this<open_token> {
virtual void accept(visitor &v) override {
std::shared_ptr<open_token> p{shared_from_this()};
v.accept(p);
}
};
The concrete visitor doesn't change by much:
struct scan : public visitor {
virtual void accept(std::shared_ptr<text_token>) override {
std::cout << "accepting text" << std::endl;
}
virtual void accept(std::shared_ptr<open_token>) override {
std::cout << "accepting open" << std::endl;
}
};
Now we can define a range of std::shared_ptrs to tokens
int main() {
std::vector<std::shared_ptr<token>> toks;
toks.push_back(std::make_shared<text_token>());
toks.push_back(std::make_shared<open_token>());
And call accept on them:
scan s;
for(auto p: toks)
p->accept(s);
}
When run, it prints:
$ ./a.out
accepting text
accepting open
Full Code
#include <memory>
#include <vector>
#include <iostream>
struct token;
struct visitor;
struct token {
virtual void accept(visitor &v) = 0;
};
struct text_token;
struct open_token;
struct visitor {
virtual void accept(std::shared_ptr<text_token> p) = 0;
virtual void accept(std::shared_ptr<open_token> p) = 0;
};
struct text_token : public token, public std::enable_shared_from_this<text_token> {
virtual void accept(visitor &v) override {
std::shared_ptr<text_token> p{shared_from_this()};
v.accept(p);
}
};
struct open_token : public token, public std::enable_shared_from_this<open_token> {
virtual void accept(visitor &v) override {
std::shared_ptr<open_token> p{shared_from_this()};
v.accept(p);
}
};
struct scan : public visitor {
virtual void accept(std::shared_ptr<text_token>) override {
std::cout << "accepting text" << std::endl;
}
virtual void accept(std::shared_ptr<open_token>) override {
std::cout << "accepting open" << std::endl;
}
};
int main() {
std::vector<std::shared_ptr<token>> toks;
toks.push_back(std::make_shared<text_token>());
toks.push_back(std::make_shared<open_token>());
scan s;
for(auto p: toks)
p->accept(s);
}
I have a hirerchy of Message class and Processor class. Each processor can recieve one or more messages on the fly. As each message can have some differnt attributes, I've to downcast that message to the concrect message class, to actually process that.
As there are a no. of message classes and process classes, I don't want to use dynamic_cast.
I tried to use following code, but this is giving compile time error.
Also, I have the flexibility to attach a processor pointer with a message (if needed), but not the other way round.
class Message
{
public:
virtual const Message* const getMessage() const = 0;
};
class MA : public Message
{
public:
const MA* const getMessage() const {return this;}
void printMA() const{std::cout<<"I am MA"<<std::endl;}
};
class MB : public Message
{
public:
const MB* const getMessage() const {return this;}
void printMB() const{std::cout<<"I am MB"<<std::endl;}
};
class Processor
{
public:
virtual void process(const Message* m) = 0;
};
class PA : public Processor
{
public:
void process(const Message* m) {processM(m->getMessage());}
void processM(const MA* m) {m->printMA();}
void processM(const MB* m) {m->printMB();}
};
int main()
{
Message* m1 = new MA();
Message* m2 = new MB();
Processor* p1 = new PA();
p1->process(m1);
p1->process(m2);
return 0;
}
I used 'double dispatch' finally to get around this. Now, the only thing is that I need to add a function in MessageProcessor' class, whenever i add a new message type., but i think that is fine.
class MessageProcessor
{
public:
virtual void process(const MA*) const{std::cout<<"unhandled:MA"<<std::endl;}
virtual void process(const MB*) const{std::cout<<"unhandled:MB"<<std::endl;}
virtual void process(const MC*) const{std::cout<<"unhandled:MC"<<std::endl;}
};
class Message
{
public:
virtual void process(const MessageProcessor*) const = 0;
};
class MA : public Message
{
public:
void printMA() const{std::cout<<"I am MA"<<std::endl;}
virtual void process(const MessageProcessor* p) const {p->process(this);}
};
class MB : public Message
{
public:
void printMB() const{std::cout<<"I am MB"<<std::endl;}
virtual void process(const MessageProcessor* p) const {p->process(this);}
};
class MC : public Message
{
public:
void printMC() const{std::cout<<"I am MC"<<std::endl;}
virtual void process(const MessageProcessor* p) const {p->process(this);}
};
class Processor : public MessageProcessor
{
public:
void processM(const Message* m){m->process(this);}
};
class PA : public Processor
{
public:
void process(const MA* m) const {m->printMA();}
void process(const MB* m) const {m->printMB();}
};
class PB : public Processor
{
public:
void process(const MA* m) const {m->printMA();}
void process(const MC* m) const {m->printMC();}
};
int main()
{
const Message* m1 = new MA();
const Message* m2 = new MB();
const Message* m3 = new MC();
Processor* p1 = new PA();
p1->processM(m1);
p1->processM(m2);
p1->processM(m3);
Processor* p2 = new PB();
p2->processM(m1);
p2->processM(m2);
p2->processM(m3);
return 0;
}
The most general solution to your problem is probably the Visitor pattern.
The simplest thing to do is eliminate the getMessage() method, and make the print() pure virtual in Message and override this in MA and MB. Furthermore, you can make process() a pure virtual method in Process and override this in PA. See code below:
#include <iostream>
class Message
{
public:
const std::string _id;
Message(std::string id):_id(id) {}
virtual void print() const = 0;
virtual void other_fun() const = 0;
};
class MA : public Message
{
private: double d_;
public:
MA():Message("MA"), d_(0.0) {}
virtual void print() const
{
std::cout<<"I am MA"<<std::endl;
std::cout << "I also have a double" << std::endl;
}
virtual void other_fun() const { std::cout << "I am MA specific" << std::endl; }
void do_hoops () const { std::cout << "Hoop!"<<std::endl;}
};
class MB : public Message
{
private: int i_;
public:
MB():Message("MB"), i_(0) {}
virtual void print() const
{
std::cout<<"I am MB"<<std::endl;
std::cout << "I also have an int"<<std::endl;
}
virtual void other_fun() const { std::cout << "I am MB specific" << std::endl; }
void do_twist() const { std::cout << "Twist!"<<std::endl; }
};
class Processor
{
public:
const std::string _id;
Processor(std::string id) : _id(id){}
virtual void process(const Message* m) = 0;
};
class PA : public Processor
{
public:
PA():Processor("PA") {}
virtual void process(const Message* m)
{
m->print();
m->other_fun();
}
};
int main()
{
Message* m1 = new MA();
Message* m2 = new MB();
// generic handling of message
Processor* p1 = new PA();
p1->process(m1);
p1->process(m2);
// message specific stuff
dynamic_cast<MA*>(m1)->do_hoops();
dynamic_cast<MB*>(m2)->do_twist();
return 0;
}
Output on Ideone.
No casts are required, the virtual functions will be selected at runtime through dynamic dispatch (virtual table lookup etc.). Message and Process are abstract base classes ("interfaces") and MA, MB and PA are concrete classes implementing these interfaces. Ideally, you also would factor the std::string state out of the Message interface, but that's left as an exercise.
Casting would be required if you would call functions that are specific to a derived class, and if you know at runtime that you are in fact calling such a class. This is done through a dynamic_cast to the particular derived class your base class pointer is currently pointing to.
You have a design flaw. Signature of Processor::process suggests it takes a Message, then it should not break this promise by trying to access something that is not a public interface of Message.
You can make Process a template class (host) that inherits from user supplied policies. Policies here are the concrete Message classes. Something like this:
#include <iostream>
struct MA
{
void print ()
{
std::cout << "MA: I'm the interface" << std::endl;
}
void printMA ()
{
std::cout << "MA: I'm special" << std::endl;
}
};
struct MB
{
void print ()
{
std::cout << "MB: I'm the interface" << std::endl;
}
void printMB ()
{
std::cout << "MB: I'm special" << std::endl;
}
};
template <typename M>
struct Process :
public M
{
void process()
{
M::print();
}
};
int main ()
{
Process<MA> p1;
Process<MB> p2;
p1.print(); // MA: I'm the interface
p1.printMA(); // MA: I'm special
p2.print(); // MB: I'm the interface
p2.printMB(); // MB: I'm special
}
Policies have print method that defines its interface. They also have some special methods like printMA and printMB. Host class (here Process) acts as user's interface to the policies. It can use the interface methods from policy classes. Special policy methods can be invoked by the user through host class.
You've run into a limitation of C++. What you really want is for the polymorphism to work on the arguments to a method, not just the method that the arguments are called on. It's generally referred to as double dispatch. Unfortunately, while there are some kind-of work-arounds, I haven't seen any perfect ones. That Wikipedia article shows the generally accepted workaround (using the Visitor pattern).
Edit: Per some comments, by simple I mean a) less code, b) easy to maintain, and c) hard to get wrong.
Edit #2: Also, using containment instead of private inheritance is not objectionable if it does indeed simplify the implementation of InterfaceImpl.
Currently, the only way I know to do this is to have the implementer define the abstract method and delegate the call to the target base type's method. Example:
#include <iostream>
#include <memory>
class Interface
{
public:
virtual void method1() = 0;
virtual void method2(int x) = 0;
};
class MethodOneImpl
{
private:
void method1(int x)
{ std::cout << "MethodOneImpl::method1() " << x << std::endl; }
public:
void method1() { method1(0); }
};
class MethodTwoImpl
{
public:
void myFunc(int x)
{ std::cout << "MethodTwoImpl::myFunc(x)" << x << std::endl; }
};
class InterfaceImpl : public Interface
, private MethodOneImpl
, private MethodTwoImpl
{
public:
virtual void method1() { MethodOneImpl::method1(); }
virtual void method2(int x) { MethodTwoImpl::myFunc(x); }
};
int main()
{
std::unique_ptr<Interface> inf;
inf.reset(new InterfaceImpl);
inf->method1();
inf->method2(0);
// This should be disallowed!
// std::unique_ptr<MethodOneImpl> moi;
// moi.reset(new InterfaceImpl);
}
At first, I thought that perhaps this might solve the problem:
class InterfaceImpl : public Interface
, private MethodOneImpl
, private MethodTwoImpl
{
public:
using MethodOneImpl::method1;
// Obviously this wouldn't work as the method names don't match.
//using MethodTwoImpl::???
};
The first using statement will make both MethodOneImpl::method1 methods be public, but it actually doesn't fulfill the contract with Interface, and it modifies the accessibility of MethodOneImpl::method1(int). And obviously we couldn't use this solution with method2 as the names don't match up.
FWIW, I have what I think is a solution, but it is not part of the standard at all (in other words it won't compile). I was thinking of making a proposal to the C++ committee; if anyone has any advice, I'd appreciate any comments below (but please dont' submit the advice as an answer).
An other option (at least if using MS VC++) is to use virtual inheritance:
struct MyInterface
{
virtual void Method1() = 0;
virtual void Method2() = 0;
};
class Method1Impl : public virtual MyInterface
{
virtual void Method1() { _tprintf( _T("Method1\n") ); }
};
class Method2Impl : public virtual MyInterface
{
virtual void Method2() { _tprintf( _T("Method2\n") ); }
};
class InterfaceImpl : public virtual MyInterface,
private Method1Impl,
private Method2Impl
{
};
void TestWeirdInterfaceImpl()
{
MyInterface* pItf = new InterfaceImpl();
pItf->Method1();
pItf->Method2();
}
While this seems to work and satisfy what you are looking for (asside from C4250 warning that you will have to suppress with a #pragma), this wouldn't be my approach. (I believe virtual inheritance is still not something that supported across all compilers, but I could be wrong).
I would probably go with containment and once boilerplate code is identifier, wrap it into some kind of macro map (similar to maps in ATL or MFC) that would make it really, really difficult to ever screw it up.
So this would be my macro approach:
struct MyInterface
{
virtual float Method1( int x ) = 0;
virtual int Method2( float a, float b ) = 0;
virtual void Method3( const TCHAR* sz ) = 0;
};
class Method1Impl
{
public:
float Method1( int x ) {
_tprintf( _T("Method1: %d\n"), x ); return 5.0;
}
};
class Method2and3Impl
{
public:
int Method2( float a, float b ) {
_tprintf( _T("Method2: %f, %f\n"), a, b ); return 666;
}
void Method3( const TCHAR* sz ) {
_tprintf( _T("Method3: %s"), sz );
}
};
#define DECLARE_METHOD0( MethodName, Obj, R ) \
virtual R MethodName() { return Obj.MethodName(); }
#define DECLARE_METHOD1( MethodName, Obj, R, A1 ) \
virtual R MethodName( A1 a1 ) { return Obj.MethodName( a1 ); }
#define DECLARE_METHOD2( MethodName, Obj, R, A1, A2 ) \
virtual R MethodName( A1 a1, A2 a2 ) { return Obj.MethodName( a1, a2 ); }
class InterfaceImpl : public MyInterface
{
public:
DECLARE_METHOD1( Method1, m_method1Impl, float, int );
DECLARE_METHOD2( Method2, m_method2and3Impl, int, float, float );
DECLARE_METHOD1( Method3, m_method2and3Impl, void, const TCHAR* );
private:
Method1Impl m_method1Impl;
Method2and3Impl m_method2and3Impl;
};
void TestWeirdInterfaceImpl()
{
MyInterface* pItf = new InterfaceImpl();
pItf->Method1( 86 );
pItf->Method2( 42.0, 24.0 );
pItf->Method3( _T("hi") );
}
Until C++ gods grace us with variadic macros, you'll have to declare one for each number of parameters you have. Also if you used multiple inheritance, potentially you wouldn't need the second "Obj" param, but as I've said before, I'd avoid multiple inheritance if there's another solution, which in this case is one extra param.
Yet a third option could be something that authors of Pragmatic Programmer seem to advocate a lot. If you have a ton of cookie cutter code that you don't want to repeat because, as you pointed out, it introduces human error. Define your own language and write a code generator script (python, perl...) to auto-create the actual code. In this case you could almost point at an interface, and have the script write the text out for you. I haven't tried doing this kind of thing myself, but lately have been wanting to use it somewhere just to see and evaluate the outcome.
This is sort of ugly and may bloat the executable size, but what about
#include <iostream>
class Interface
{
public:
virtual void method1() = 0;
virtual void method2(int x) = 0;
};
template<typename T>
class MethodOneImpl : public T
{
private:
void method1(int x)
{ std::cout << "MethodOneImpl::method1() " << x << std::endl; }
public:
void method1() { method1(0); }
};
template<typename T>
class MethodTwoImpl : public T
{
public:
void method2(int x)
{ std::cout << "MethodTwoImpl::myFunc(x)" << x << std::endl; }
};
class InterfaceImpl : public MethodTwoImpl<MethodOneImpl<Interface> >
{
};
int main()
{
InterfaceImpl impl;
impl.method1();
impl.method2(0);
}
class AbsInterface
{
// this is a simple interface class.
public:
virtual void Method1() = 0;
virtual void Method2() = 0;
};
class Functor1
{
public:
void operator () ()
{
printf("This Is Void Functor1");
}
};
class Functor2
{
public:
void operator () ()
{
printf("This Is void Functor2");
}
};
template <class T1, class T2>
class DerivedTemplateClass : public AbsInterface
{
public:
virtual void Method1() { T1()(); }
virtual void Method2() { T2()(); }
};
void main()
{
DerivedTemplateClass<Stratege1, Stratege2> instance;
instance.Method1();
instance.Method2();
}
as you can see, I used Functor.
You could work with template and functor.
It seems impossible to bring MethodOneImpl / MethodTwoImpl into the scope of Interface without having them inherit from Interface because they will not fill the Virtual Table if they don't. C++ misses something like the keyword implements from other languages.
So you are stuck with the virtual inheritence thing unless realize/accept that what you are looking for is just a bridge pattern, which does not satisfy requirement a) (you shall write more code), midly b) (code not necessarly difficult to maintain) and may satisfy c).
Here (another) possible solution (with only method though to reduce bloat)
class Interface
{ public:
virtual void method1() {return impl_->method1();}
private:
Interface() {}
protected:
struct Impl {
virtual void method1() = 0; };
std::shared_ptr<Impl> impl_;
Interface(const std::shared_ptr<Impl> &impl) : impl_(impl) {}
};
class InterfaceImpl : public Interface
{
struct Impl : public Interface::Impl {
void method1() { std::cout << "InterfaceImpl::method1() " << std::endl; } } ;
public:
InterfaceImpl() : Interface(std::shared_ptr<Impl> (new Impl)) {}
};
template <class T>
class GenericInterfaceImpl : public Interface {
struct Impl : public Interface::Impl {
Impl( T &t) : t_(t) {}
void method1() { t_.method1() ; }
T t_; };
public:
GenericInterfaceImpl() : Interface(std::shared_ptr<Impl> (new Impl(T()))) {}
};
struct AMethod1Impl {
void method1() { std::cout << "AMethod1Impl::method1() " << std::endl; } } ;
struct AnotherMethod1Impl_not_working {
void method1_not_present() { std::cout << "AnotherMethod1Impl_not_working ::method1_not_present() " << std::endl; } } ;
int main() {
// compilation of next line would fail
// (lame attempt to simulate ompilation fail when pure function not implemented)
// Interface inf;
std::unique_ptr<Interface> inf;
inf.reset(new InterfaceImpl);
inf->method1();
inf.reset(new GenericInterfaceImpl<AMethod1Impl>() );
inf->method1();
// compilation of next line would fail
// inf.reset(new GenericInterfaceImpl<AnotherMethod1Impl_not_working>() );
}
Does this serve your purpose?
It maintains the interface relationship and gives you maintainable code without having any consideration of client code.
Separating each method in functionoid and giving you the power to control the prototype of each method of the different base class.
#include <iostream>
#include <memory>
using namespace std;
//No Control over this.
class MethodOneImpl
{
private:
void method1(int x)
{ std::cout << "MethodOneImpl::method1() " << x << std::endl; }
public:
void method1() { method1(0); }
};
class MethodTwoImpl
{
public:
void myFunc(int x)
{ std::cout << "MethodTwoImpl::myFunc(x)" << x << std::endl; }
};
//*************************//
class Interface
{
public:
virtual void method1() = 0;
virtual void method2(int x) = 0;
};
//This is what i would do. //
class BaseFuncType
{
//no pure virtual
void Call()
{
throw "error";
}
void Call(int x)
{
throw "error";
}
};
class Method1: public BaseFuncType
{
auto_ptr<MethodOneImpl> MethodPtr;
public:
Method1()
{
MethodPtr.reset(new MethodOneImpl());
}
virtual int Call()
{
MethodPtr->method1();
}
};
class Method2: public BaseFuncType
{
auto_ptr<MethodTwoImpl> MethodPtr;
public:
Method2()
{
MethodPtr.reset(new MethodTwoImpl());
}
virtual int Call(int x)
{
MethodPtr->myFunc(x);
}
};
template <class T1>
class MethodFactory
{
private:
T1 methodObj;
public:
void CallMethod()
{
methodObj.Call();
}
void CallMethod(int x)
{
methodObj.Call(x);
}
};
class InterfaceImpl : public Interface
{
auto_ptr<MethodFactory> factory;
public:
virtual void method1()
{
factory.reset(new MethodFactory<Method1>());
factory->CallMethod();
}
virtual void method2(int x)
{
factory.reset(new MethodFactory<Method2>());
factory->CallMethod(x);
}
};
int main()
{
auto_ptr<Interface> inf;
inf.reset(new InterfaceImpl);
inf->method1();
inf->method2(10);
// This should be disallowed!
// std::unique_ptr<MethodOneImpl> moi;
// moi.reset(new InterfaceImpl);
}
I've currently got a class that can notify a number of other objects via callbacks:
class Callback {
virtual NodulesChanged() =0;
virtual TurkiesTwisted() =0;
};
class Notifier
{
std::vector<Callback*> m_Callbacks;
void AddCallback(Callback* cb) {m_Callbacks.push(cb); }
...
void ChangeNodules() {
for (iterator it=m_Callbacks.begin(); it!=m_Callbacks.end(); it++) {
(*it)->NodulesChanged();
}
}
};
I'm considering changing this to use boost's signals and slots as it would be beneficial to reduce the likelihood of dangling pointers when the callee gets deleted, among other things. However, as it stands boost's signals seems more oriented towards dealing with function objects. What would be the best way of adapting my code to still use the callback interface but use signals and slots to deal with the connection and notification aspects?
Compared to my other answer, this solution is much more generic and eliminates boilerplate code:
#include <iostream>
#include <boost/bind.hpp>
#include <boost/signal.hpp>
///////////////////////////////////////////////////////////////////////////////
// GENERIC REUSABLE PART FOR ALL SUBJECTS
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
template <class CallbackType>
class CallbackInvoker
{
public:
virtual ~CallbackInvoker() {}
virtual void operator()(CallbackType* callback) const {};
};
//-----------------------------------------------------------------------------
template <class CallbackType, class Binding>
class BoundInvoker : public CallbackInvoker<CallbackType>
{
public:
BoundInvoker(const Binding& binding) : binding_(binding) {}
void operator()(CallbackType* callback) const {binding_(callback);}
private:
Binding binding_;
};
//-----------------------------------------------------------------------------
template <class CallbackType>
class CallbackSlot
{
public:
CallbackSlot(CallbackType* callback) : callback_(callback) {}
void operator()(const CallbackInvoker<CallbackType>& invoker)
{invoker(callback_);}
private:
CallbackType* callback_;
};
//-----------------------------------------------------------------------------
template <class CallbackType>
class Subject
{
public:
virtual ~Subject() {}
boost::signals::connection Connect(CallbackType* callback)
{return signal_.connect(CallbackSlot<CallbackType>(callback));}
protected:
template <class Binding> void Signal(const Binding& binding)
{
signal_(BoundInvoker<CallbackType,Binding>(binding));
}
private:
boost::signal<void (const CallbackInvoker<CallbackType>&)> signal_;
};
///////////////////////////////////////////////////////////////////////////////
// THIS PART SPECIFIC TO ONE SUBJECT
///////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------------
class MyCallback
{
public:
virtual ~MyCallback() {}
virtual void NodulesChanged() =0;
virtual void TurkiesTwisted(int arg) =0;
};
//-----------------------------------------------------------------------------
class FooCallback : public MyCallback
{
public:
virtual ~FooCallback() {}
void NodulesChanged() {std::cout << "Foo nodules changed\n";}
void TurkiesTwisted(int arg)
{std::cout << "Foo " << arg << " turkies twisted\n";}
};
//-----------------------------------------------------------------------------
class BarCallback : public MyCallback
{
public:
virtual ~BarCallback() {}
void NodulesChanged() {std::cout << "Bar nodules changed\n";}
void TurkiesTwisted(int arg)
{std::cout << "Bar " << arg << " turkies twisted\n";}
};
//-----------------------------------------------------------------------------
class MySubject : public Subject<MyCallback>
{
public:
void OnNoduleChanged()
{this->Signal(boost::bind(&MyCallback::NodulesChanged, _1));}
void OnTurkiedTwisted(int arg)
{this->Signal(boost::bind(&MyCallback::TurkiesTwisted, _1, arg));}
};
///////////////////////////////////////////////////////////////////////////////
// CLIENT CODE
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
int main()
{
MySubject subject;
FooCallback fooCb;
BarCallback barCb;
subject.Connect(&fooCb);
subject.Connect(&barCb);
subject.OnNoduleChanged();
subject.OnTurkiedTwisted(42);
}
Hooray for boost::bind! :-)
boost::signals is pretty flexible when it comes to what you bind to a signal. You can use a function object, but you can also just use a function pointer or use boost::bind to make almost any kind of function into a function object. Here is what your example might look like, although there may be better ways.
#include <boost/signals.hpp>
class Notifier
{
public:
boost::signal< void() > NodulesChanged;
void ChangeNodules()
{
//Just call the signal and all connected slots will be called.
NodulesChanged();
}
};
To add a callback, you can simply
void callback1()
{
//do callback stuff
}
void callback2()
{
//do callback stuff
}
int main()
{
Notifier n;
n.NodulesChanged.connect(&callback1);
n.NodulesChanged.connect(&callback2);
//calls callback1 & 2.
n.ChangeNodules();
}
If you wanted to connect a member function with arguments as a slot, you could do something like this:
class Notifier
{
public:
boost::signal< void ( double ) > ProgressSignal;
};
class OtherClass
{
public:
void UpdateProgress(double pct);
};
int main()
{
Notifier n;
OtherClass oc;
n.ProgressSignal.connect(boost::bind(&OtherClass::UpdateProgress, &oc, _1));
//Calls oc.UpdateProgress(0);
n.ProgressSignal(0);
}
Warning: None of this has been compiled or tested.
This solution allows you to use the same signal object even if Callback's methods have different signatures.
#include <iostream>
#include <boost/signal.hpp>
//------------------------------------------------------------------------------
class Callback
{
public:
virtual void NodulesChanged() =0;
virtual void TurkiesTwisted(int arg) =0;
};
//------------------------------------------------------------------------------
class FooCallback : public Callback
{
public:
void NodulesChanged() {std::cout << "Foo nodules changed\n";}
void TurkiesTwisted(int arg) {std::cout << "Foo " << arg << " turkies twisted\n";}
};
//------------------------------------------------------------------------------
class BarCallback : public Callback
{
public:
void NodulesChanged() {std::cout << "Bar nodules changed\n";}
void TurkiesTwisted(int arg) {std::cout << "Bar " << arg << " turkies twisted\n";}
};
//------------------------------------------------------------------------------
class CallbackInvoker
{
public:
virtual void operator()(Callback* callback) const {};
};
//------------------------------------------------------------------------------
class NoduleChangedInvoker : public CallbackInvoker
{
public:
void operator()(Callback* callback) const {callback->NodulesChanged();}
};
//------------------------------------------------------------------------------
class TurkiesTwistedInvoker : public CallbackInvoker
{
public:
TurkiesTwistedInvoker(int arg) : arg_(arg) {}
void operator()(Callback* callback) const {callback->TurkiesTwisted(arg_);}
private:
int arg_;
};
//------------------------------------------------------------------------------
class CallbackSlot
{
public:
CallbackSlot(Callback* callback) : callback_(callback) {}
void operator()(const CallbackInvoker& invoker) {invoker(callback_);}
private:
Callback* callback_;
};
//------------------------------------------------------------------------------
class Subject
{
public:
typedef boost::signal<void (const CallbackInvoker&)> SignalType;
boost::signals::connection Connect(Callback* callback)
{return signal_.connect(CallbackSlot(callback));}
void OnNoduleChanged() {signal_(NoduleChangedInvoker());}
void OnTurkiedTwisted(int arg) {signal_(TurkiesTwistedInvoker(arg));}
private:
SignalType signal_;
};
//------------------------------------------------------------------------------
int main()
{
Subject subject;
FooCallback fooCb;
BarCallback barCb;
subject.Connect(&fooCb);
subject.Connect(&barCb);
subject.OnNoduleChanged();
subject.OnTurkiedTwisted(42);
}
This outputs:
Foo nodules changed
Bar nodules changed
Foo 42 turkies twisted
Bar 42 turkies twisted
CallbackSlot is the function object stored in the boost::signal, and contains a pointer to a concrete Callback object. When you invoke the boost::signal, you have to pass it a CallbackInvoker concrete object which bundles any callback arguments and which knows how to invoke the appropriate Callback method.
There might be a way to avoid the CallbackInvoker boilerplate code using Boost.Lamda, but I'm not very familiar with that Boost library.
You'll probably want to use boost::shared_ptr<Callback> instead of Callback* to avoid memory leaks and dangling pointers.