C++ XML Objects Use: Add new stuff

Previous Next Usage Home Installation Docs

Abstract

OK, now the rubber meets the road. Let's add all of the new stuff to ready our simple objects.

Description

I'll get straight to the code added to each object, then I'll go back and describe the bits:

class root : public ph::xmlobj::xmlobj
{
private:
	int x;
	ph::xmlobj::xmlobj_typed_vector<foo> foos;
	ph::xmlobj::xmlobj_typed_vector<bar> bars;
	ph::xmlobj::xmlobj_typed_ref<foo> a_foo;
	
public:
	root(const std::string &type, const std::string &name) :
		xmlobj(type, name),
		x(0),
		foos(this, "foos"),
		bars(this, "bars"),
		a_foo(this, "a_foo")
			{};
	
	// the copy constructor.
	void copy(const root &obj);
	
	// xmlobj overrides
	virtual bool accept(ph::common::member_visitor *v);
	virtual bool accept(ph::common::const_member_visitor *v) const;
	virtual bool accept(ph::common::object_visitor *v);
	virtual bool accept(ph::common::const_object_visitor *v) const;
	virtual ph::common::object_base *clone(const std::string &name, 
		ph::common::cloneable_object_context *context) const;
};

class foo : public ph::xmlobj::xmlobj
{
private:
	int x;
	double y;
	bool z;
	
public:
	foo(const std::string &type, const std::string &name) : 
		xmlobj(type, name), 
		x(0), 
		y(0),
		z(false)
			{};

	// the copy constructor.
	void copy(const foo &obj);
	
	// xmlobj overrides
	virtual bool accept(ph::common::member_visitor *v);
	virtual bool accept(ph::common::const_member_visitor *v) const;
	virtual bool accept(ph::common::object_visitor *v);
	virtual bool accept(ph::common::const_object_visitor *v) const;
	virtual ph::common::object_base *clone(const std::string &name, 
		ph::common::cloneable_object_context *context) const;
};

class bar : public foo
{
private:
	int a;
	double b;
	int c;
	
public:
	bar(const std::string &type, const std::string &name) : 
		foo(type, name), 
		a(0), 
		b(0), 
		c(0)
			{};

	// the copy constructor.
	void copy(const bar &obj);

	// xmlobj overrides
	virtual bool accept(ph::common::member_visitor *v);
	virtual bool accept(ph::common::const_member_visitor *v) const;
	virtual bool accept(ph::common::object_visitor *v);
	virtual bool accept(ph::common::const_object_visitor *v) const;
	virtual ph::common::object_base *clone(
		const std::string &name, ph::common::cloneable_object_context *context) const;
};

Once again Forget about things like correct includes for STL, namespaces etc. The point is that you need to add the following things to your code:

The copy() function is used in conjunction with clone() to implement the Prototype pattern for your object so that the code can create a new object at a later date. This means that to register objects you simply create one of each type. the whole idea of cloning is very important for a major feature of cppxmlobj which is that you can define template objects which others derived from.

The accept() methods are used for visiting the object hierarchy while parsing and assigning new values to your members. A general visitor pattern was implemented rather than some type of mapping routine because it makes the setting/getting of objects a specific case of a much more general and useful feature.

I also glossed over the fact that I have replaced your vectors and pointers with objects. Internally, xmlobj_typed_vector and xmlobj_typed_ref are implemented as a std::vector and a pointer respectively, but they do much more for you:

Let's look at the implementation of our methods we added:

void root::copy(const root &obj)
{
	xmlobj::copy(obj);
	x = obj.x;
	foos.copy(this, obj.foos);
	bars.copy(this, obj.bars);
	a_foo.copy(this, obj.a_foo);
}

All of the copy's look like this. They copy the members with a simple assigning (since there just POD's) and then they copy the vectors and refs with these object's copy().

bool root::accept(ph::common::object_visitor *v)
{	
	if (!xmlobj::accept(v)) return false;
	if (!foos.accept(v)) return false;
	if (!bars.accept(v)) return false;
	if (!a_foo.accept(v)) return false;
	return true;
}

All of the accept's for object_visitor look like this. They call their inherited object's accept, and then they visit all of the members which are composites of other objects.

bool foo::accept(ph::common::member_visitor *v)
{	
	if (!xmlobj::accept(v)) return false;
	ph::reflect::pod_member<int> _x(&x); 
	if (!v->visit(this, "x", &_x)) 
		return false;
	ph::reflect::pod_member<double> _y(&y); 
	if (!v->visit(this, "y", &_y)) 
		return false;
	ph::reflect::pod_member<bool> _z(&z); 
	if (!v->visit(this, "z", &_z)) 
		return false;
	return true;
}

Foo has some POD members, so we do the above. The "name" of the member appears in the string as the second arg to visit(). We also pass the object in when visiting so that visitors can be more general.

bool bar::accept(ph::common::member_visitor *v)
{	
	if (!foo::accept(v)) return false;
	ph::reflect::pod_member<int> _a(&a); 
	if (!v->visit(this, "a", &_a)) 
		return false;
	ph::reflect::pod_member<double> _b(&b); 
	if (!v->visit(this, "b", &_b)) 
		return false;
	ph::reflect::pod_member<int> _c(&c); 
	if (!v->visit(this, "c", &_c)) 
		return false;
	return true;
}

Bar has some POD members, but it is actually a "foo". We always visit our superclass first to catch all of it's members.

The "const" accepts() are identical to the above, except that they use ph::reflect::const_pod_member templates instead. The reason for special const accept() methods is so that visitors can be written which correctly adhere to constness. They will not be allowed to write the member.

ph::common::object_base *root::clone(const std::string &name, 
	ph::common::cloneable_object_context *context) const
{ 
	return xmlobj_clone(this, name, context); 
}

Our clone method uses a template called "xmlobj_clone()" which is explicitly instantiated against the type of "this". So it always appears the same.

Straight away you are thinking "Every time I add a new member, I need to add a whole bunch of lines to a whole bunch of methods the implementation file".

Previous Next Usage Home Installation Docs


Generated: Wed Apr 5 23:00:19 EST 2006

Copyright (c) 2005; Paul Hamilton; pHamtec P/L.

Use, modification, and distribution is provided free of any limitations.