design issue

M

Mark P

I recently wrote a medium sized package to do some tasks in
computational geometry. I define basic items like Points, Edges, and
Polygons, and then more advanced operations that work with these items,
for example, computing intersection points or performing geometric
Boolean operations (unions, intersections, etc.).

Now I want to provide additional optional features, for example, maybe
Points will be able to contain a short list of extra data that can be
propagated through the algorithms and in some way appear in the output.
The problem I have is that all of my data structures seem intricately
dependent upon one another. I could derive from Point to make DataPoint
(a point + data), but then I'll need a DataEdge with 2 endpoint
DataPoints (since my Edges "own" their endpoints), I'll need a
DataPolygon which works with DataPoints, etc. I also make liberal use
of STL container classes (for example, a Polygon derives from
std::list<Point>) which seem inhospitable to inheritance unless I want
to contain only pointers (which I do for large items, but find tedious
for smaller items that aren't copied ever).

I'm sure this issue is a common one, and I'm equally sure there must be
a long std::list<Better Ideas> that would ease my pain. I'd be grateful
for any suggestions on this.

Thanks,
Mark
 
J

Jonathan Mcdougall

I recently wrote a medium sized package to do some tasks in
computational geometry. I define basic items like Points, Edges, and
Polygons, and then more advanced operations that work with these
items, for example, computing intersection points or performing
geometric Boolean operations (unions, intersections, etc.).
Now I want to provide additional optional features, for example, maybe
Points will be able to contain a short list of extra data that can be
propagated through the algorithms and in some way appear in the output.

The problem I have is that all of my data structures seem intricately
dependent upon one another. I could derive from Point to make
DataPoint (a point + data), but then I'll need a DataEdge with 2 endpoint
DataPoints (since my Edges "own" their endpoints), I'll need a
DataPolygon which works with DataPoints, etc.

What about making these classes templates?

template <class P>
class Edge
{
private:
P a, b;

public:
...
}
I also make liberal use
of STL container classes (for example, a Polygon derives from
std::list<Point>) which seem inhospitable to inheritance unless I want
to contain only pointers (which I do for large items, but find tedious
for smaller items that aren't copied ever).

Be careful since containers do not have virtual destructors. What
about aggregating a std::list?
I'm sure this issue is a common one, and I'm equally sure there must be
a long std::list<Better Ideas> that would ease my pain. I'd be grateful
for any suggestions on this.

# include <iostream>

class Point
{
public:
int x, y;

void show()
{
std::cout << x << y;
}
};

class DataPoint
{
public:
int x, y;
Data d;

void show()
{
std::cout << x << y << d;
}
};

template <class P>
class Edge
{
private:
P a, b;

public:
void go()
{
a.show(); b.show();
}
};

int main()
{
Edge<Point> e; e.go(); // ok
Edge<DataPoint> de; de.go(); // ok
Edge<int> ie; ie.go(); // error
}

Jonathan
 
G

Guest

I recently wrote a medium sized package to do some tasks in computational
geometry. I define basic items like Points, Edges, and Polygons, and
then more advanced operations that work with these items, for example,
computing intersection points or performing geometric Boolean operations
(unions, intersections, etc.).

Now I want to provide additional optional features, for example, maybe
Points will be able to contain a short list of extra data that can be
propagated through the algorithms and in some way appear in the output.
The problem I have is that all of my data structures seem intricately
dependent upon one another. I could derive from Point to make DataPoint
(a point + data), but then I'll need a DataEdge with 2 endpoint
DataPoints (since my Edges "own" their endpoints), I'll need a
DataPolygon which works with DataPoints, etc. I also make liberal use of
STL container classes (for example, a Polygon derives from
std::list<Point>) which seem inhospitable to inheritance unless I want to
contain only pointers (which I do for large items, but find tedious for
smaller items that aren't copied ever).

I'm sure this issue is a common one, and I'm equally sure there must be a
long std::list<Better Ideas> that would ease my pain. I'd be grateful
for any suggestions on this.

Thanks,
Mark

You may have a look at the boost graph library at

http://www.boost.org/libs/graph/doc/table_of_contents.html


+ algorithms and iterators.

Your data structures are linked together, not necesserily dependent
on each other.
 
P

__PPS__

Jonathan Mcdougall wrote:
.....
# include <iostream>

class Point
{
public:
int x, y;

void show()
{
std::cout << x << y;
}
};

class DataPoint
{
public:
int x, y;
Data d;

void show()
{
std::cout << x << y << d;
}
};

template <class P>
class Edge
{
private:
P a, b;

public:
void go()
{
a.show(); b.show();
}
};

int main()
{
Edge<Point> e; e.go(); // ok
Edge<DataPoint> de; de.go(); // ok
Edge<int> ie; ie.go(); // error
}

Jonathan

I always prefer it like this:

#include <iostream>

struct point {
int x, y;
friend std::eek:stream& operator<<(std::eek:stream& s, const point& p){
return s << '(' << p.x << ", " << p.y << ')';
}
};

struct dataPoint : public point {
Data d;
friend std::eek:stream& operator<<(std::eek:stream& s, const dataPoint&
dp){
return s << (const& point)dp << ' ' << dp.d;
}
};

template <class P>
class edge {
private:
P a, b;
friend std::eek:stream& operator<<(std::stream& s, const egde& e){
return s << e.a << e.b;
}
};

int main(){
edge<point> e; std::cout << e << std::endl;
edge<dataPoint> de; std::cout << de << std::endl;
edge<int> ie; std::cout << ie << std::endl;
}
 
J

Jonathan Mcdougall

I always prefer it like this:
#include <iostream>

struct point {
int x, y;
friend std::eek:stream& operator<<(std::eek:stream& s, const point& p){
return s << '(' << p.x << ", " << p.y << ')';
}

What do you gain by making it a friend?
};

struct dataPoint : public point {

What's the use of inheritance here?
Data d;
friend std::eek:stream& operator<<(std::eek:stream& s, const dataPoint&
dp){
return s << (const& point)dp << ' ' << dp.d;

This should be

return s << (const point&)dp << ' ' << dp.d;
^
and prefer C++ casts:

return s said:
}

};

template <class P>
class edge {
private:
P a, b;
friend std::eek:stream& operator<<(std::stream& s, const egde& e){

This should be

friend std::eek:stream& operator<<(std::eek:stream& s, const edge& e){
^ ^
return s << e.a << e.b;
}

};

<snip>

Please compile your code first before posting.

Jonathan
 
P

__PPS__

Jonathan said:
What do you gain by making it a friend?

Does the keyword friend scare you? Even if it doesn't access private
members it still can be friend. I just use it like this to put
operator<< code inside class definition and not somewhere else, in
which case, of course, it could be a usual global function
operator<<(...)
What's the use of inheritance here?

What's wrond with that? dataPoint is a point that has some extra Data
d. Do you prefer to copy-paste class point{...}; and add some extra
members? - you are free to do it your way :) (don't forget that point
may be changet latter, and probably dataPoint also)
This should be

return s << (const point&)dp << ' ' << dp.d;
^
and prefer C++ casts:

I know how to use c++ casts, but the code I wrote has no problems...
This should be

friend std::eek:stream& operator<<(std::eek:stream& s, const edge& e){
^ ^

<snip>

Please compile your code first before posting.

Did you try? Did it work? :) I hope I didn't mistype somewhere ... :)
 
B

Bart van Ingen Schenau

Mark said:
I recently wrote a medium sized package to do some tasks in
computational geometry. I define basic items like Points, Edges, and
Polygons, and then more advanced operations that work with these
items, for example, computing intersection points or performing
geometric Boolean operations (unions, intersections, etc.).

Now I want to provide additional optional features, for example, maybe
Points will be able to contain a short list of extra data that can be
propagated through the algorithms and in some way appear in the
output.
The problem I have is that all of my data structures seem
intricately
dependent upon one another. I could derive from Point to make
DataPoint (a point + data), but then I'll need a DataEdge with 2
endpoint DataPoints (since my Edges "own" their endpoints), I'll need
a
DataPolygon which works with DataPoints, etc. I also make liberal use
of STL container classes (for example, a Polygon derives from
std::list<Point>) which seem inhospitable to inheritance unless I want
to contain only pointers (which I do for large items, but find tedious
for smaller items that aren't copied ever).

I'm sure this issue is a common one, and I'm equally sure there must
be
a long std::list<Better Ideas> that would ease my pain. I'd be
grateful for any suggestions on this.

My suggestion would be to to change Point such that it contains (a
pointer to) zero or one AdditionalData objects (optionally, you could
make that zero or more).
With an accessor function you can retrieve the AdditionalData when you
need it or you get a NULL pointer if the Point does not have any
AdditionalData.
Thanks,
Mark

Bart v Ingen Schenau
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,294
Messages
2,571,511
Members
48,200
Latest member
SCPKatheri

Latest Threads

Top