Sign in to follow this  
Josiahmazing

C++ Provide an interface without inheriting from it using an inner class

Recommended Posts

My first post here.. Hoping for some critiques on this technique, I haven't seen it in any of the c++ books I've read. If there is a better way to accomplish this please share! This code allows a class to provide an interface without the requirement of inheriting from the interface class itself. Here is the original project I wrote to test the idea.
#include <iostream>
using std::cout;
#include <vector>
using std::vector;

class IActionListener
{
public:
	virtual void ActionPerformed(int actionEvent)=0;
};

class CActionMaker
{
public:
	void AddActionListener(IActionListener* listener)
	{
		// prevent duplicates
		for (ListenerList::iterator itr = m_Listeners.begin(); itr != m_Listeners.end(); ++itr) {
			if (listener == (*itr))
				return;
		}
		m_Listeners.push_back(listener);
	}

	void RemoveActionListener(IActionListener* listener)
	{
		for (ListenerList::iterator itr = m_Listeners.begin(); itr != m_Listeners.end(); ++itr) {
			if (listener == (*itr)) {
				m_Listeners.erase(itr);
				return;
			}
		}
	}

	//
	// A few sample functions that may trigger an event
	//

	void Move()
	{
		cout << "CActionMaker::Move() (Event 0)\n";
		Notify(0);
	}

	void Click()
	{
		cout << "CActionMaker::Click() (Event 1)\n";
		Notify(1);
	}

	void Type()
	{
		cout << "CActionMaker::Type() (Event 2)\n";
		Notify(2);
	}

	void Resize()
	{
		cout << "CActionMaker::Resize() (Event 3)\n";
		Notify(3);
	}


private:
	void Notify(int actionEvent)
	{
		for (ListenerList::iterator itr = m_Listeners.begin(); itr != m_Listeners.end(); ++itr) {
			(*itr)->ActionPerformed(actionEvent);
		}
	}

	typedef vector<IActionListener*> ListenerList;
	ListenerList m_Listeners;
};

class COuter
{
public:
	COuter()
	:m_Inner(GetRef()) // GetRef() written and called to prevent WARNING C4355
	{}
	
	IActionListener * GetActionListener()
	{
		return &m_Inner;
	}
private:
	void DoAction1()
	{
		cout << "COuter::DoAction1()\n";
	}
	
	void DoAction2()
	{
		cout << "Couter::DoAction2()\n";
	}

	void DoActionOther()
	{
		cout << "Couter::DoActionOther()\n";
	}


	class CInner : public IActionListener
	{
	public:
		CInner(COuter& outer)
		:m_Outer(outer)
		{}
	private:

		virtual void ActionPerformed(int actionEvent)
		{
			cout << "CInner::ActionPerformed(" << actionEvent << ")\n";
			switch (actionEvent)
			{
			case 1:
				m_Outer.DoAction1();
				break;
			case 2:
				m_Outer.DoAction2();
				break;
			default:
				m_Outer.DoActionOther();
			}
		}
	
		COuter& m_Outer;
	} m_Inner;

	COuter& GetRef()
	{
		return *this;
	}
};

class CTest
{
public:
	CTest()
	{
		m_ActionMaker.AddActionListener(m_Outer1.GetActionListener());
		m_ActionMaker.AddActionListener(m_Outer2.GetActionListener());
	}
	
	~CTest()
	{
		m_ActionMaker.RemoveActionListener(m_Outer2.GetActionListener());
		m_ActionMaker.RemoveActionListener(m_Outer1.GetActionListener());
	}
	
	void Test()
	{
		m_ActionMaker.Move();
		m_ActionMaker.Click();
		m_ActionMaker.Type();
		m_ActionMaker.Resize();
	}
private:
	CActionMaker m_ActionMaker;
	COuter m_Outer1;
	COuter m_Outer2;
};

void main()
{
	CTest test;
	test.Test();
}



Output: CActionMaker::Move() (Event 0) CInner::ActionPerformed(0) Couter::DoActionOther() CInner::ActionPerformed(0) Couter::DoActionOther() CActionMaker::Click() (Event 1) CInner::ActionPerformed(1) COuter::DoAction1() CInner::ActionPerformed(1) COuter::DoAction1() CActionMaker::Type() (Event 2) CInner::ActionPerformed(2) Couter::DoAction2() CInner::ActionPerformed(2) Couter::DoAction2() CActionMaker::Resize() (Event 3) CInner::ActionPerformed(3) Couter::DoActionOther() CInner::ActionPerformed(3) Couter::DoActionOther() Press any key to continue /edit to add source tags

Share this post


Link to post
Share on other sites
c++ doesn't currently have inner-classes like java, it has nested classes which are equivalent to a static inner class in java.

C++ doesn't really need it besides there are much better ways to do callbacks in c++, if you wont to do event handling then you might want to look into boost signals & slots library

[Edited by - snk_kid on November 30, 2004 5:38:02 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by snk_kid
c++ doesn't currently have inner-classes like java, it has nested classes which are equivalent to a static inner class in java.

C++ doesn't really need it besides there are much better ways to do callbacks in c++.


Yeah, I got the inspiration for this after working with Java for the first time recently. In Java a reference to the outer class is implicitly passed to the inner. I'm just doing it explicitly.

I'm thought I was familiar with most ways to provide callbacks in C++ but perhaps not, could you explain a better way?

Thanks

/Edit, You edited your post linking to boost::slots, will check that out!

Share this post


Link to post
Share on other sites
Quote:
Original post by Josiahmazing
Yeah, I got the inspiration for this after working with Java for the first time recently. In Java a reference to the outer class is implicitly passed to the inner. I'm just doing it explicitly.


Have you forgotten anonymous inner classes?


public interface foo {
public void bar();
}
//...
public final class foobar {

public foo do_foo() {
return new foo() { //has access to foobars internals
public void bar() {
System.out.println("hi");
}
}
};
}


Not sure if that is 100% correct but you get the point, you cant do that in c++ not that you really need to besides.

Quote:
Original post by Josiahmazing
I'm thought I was familiar with most ways to provide callbacks in C++ but perhaps not, could you explain a better way?


apart from the obvious ways, the others mostly involve advance uses of templates & generic programming, it all starts from this useless example:


#include <iostream>

template < typename T >
void foo(T bar) {

bar();

}

struct foo_functor { //functor can have state

std::ostream& out;

foo_functor(std::ostream& _out): out(_out) {}

void operator()() {
out << "hi\n";
}

};

void foo_function() {
std::cout << "hi\n";
}

int main() {

foo(foo_function);

foo(foo_functor(std::cout));

}


it goes beyond that thou.

As i was saying before if you want to do event handling for say a GUI system i recommend using signals & slots (generalized callbacks) approach boost has such a library here.

[Edited by - snk_kid on November 30, 2004 5:06:52 AM]

Share this post


Link to post
Share on other sites
You can write Java-style code in C++, but the results aren't always pretty. (I will leave discussion of this point as it relates to the core Java language for another time.)

Look up functors.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this