472,972 Members | 2,333 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,972 software developers and data experts.

Need design advice

I'm creating a library for internal use that relies on third-party code. I
don't want clients of this library to know anything about the third party
code, when compiling or running. Generally I've been achieving this by having
an abstract base class which defines an interface, and inheriting a concrete
class which defines the implementation. Clients of the library deal only with
the base class and request objects of that type from a factory function.

This works great in most cases. The problems set in when you have operator
overloading. For example, I might have a class which defines 2-dimensional
point on the screen. I want the user to be able to use operator+, operator==,
operator=, etc... on this class.

Scanning the archives of this newsgroup it seems the big problem comes into
play with operator=, although I still see problems with the other operators as
well.

Hopefully what I'm saying is clear; if not, please let me know. :-)

What I'm trying to do is analogous to:

class Point
{
virtual void function(int x) = 0;
}

class PointImplemenation
{
virtual void function(int x);
}

except with operators:

class Point
{
virtual Point operator+(const Point& pt) = 0;
}

class PointImplementation
{
virtual PointImplementation operator+(const PointImplementation& pt);
}

I don't think this is going to work well at all, and it looks like a recipe
for many headaches in the future.

Anyone have an elegant solution for this problem? I've thought of the
possibility of using a proxy object instead of direct inheritance, although
that's not so great either, IMO.

I'm open to any ideas. :-)

Thanks!

Carl

--
Remove "NOSPAM" to reply in e-mail

Jul 19 '05 #1
5 2173
"Carl Bevil" <ca**************@yahoo.com> wrote...
I'm creating a library for internal use that relies on third-party code. I don't want clients of this library to know anything about the third party
code, when compiling or running. Generally I've been achieving this by having an abstract base class which defines an interface, and inheriting a concrete class which defines the implementation. Clients of the library deal only with the base class and request objects of that type from a factory function.

This works great in most cases. The problems set in when you have operator overloading. For example, I might have a class which defines 2-dimensional point on the screen. I want the user to be able to use operator+, operator==, operator=, etc... on this class.

Scanning the archives of this newsgroup it seems the big problem comes into play with operator=, although I still see problems with the other operators as well.

Hopefully what I'm saying is clear; if not, please let me know. :-)
After reading the rest, yes, you're unclear.

What I'm trying to do is analogous to:

class Point
{
Perhaps you need

public:

here...
virtual void function(int x) = 0;
} ;

class PointImplemenation
Shouldn't this be

class PointImplementation : public Point
{
virtual void function(int x);
} ;
except with operators:

class Point
{
public:
virtual Point operator+(const Point& pt) = 0;
}

class PointImplementation
Again, you probably meant

class PointImplementation : public Point
{
virtual PointImplementation operator+(const PointImplementation& pt);
This will not be an overrider. The return values have to be
at least covariant, which means either pointers or references
to related classes. Also, _arguments_ have to be the same.
}

I don't think this is going to work well at all, and it looks like a recipe for many headaches in the future.
Yes, it's not going to work.
Anyone have an elegant solution for this problem? I've thought of the
possibility of using a proxy object instead of direct inheritance, although that's not so great either, IMO.
That's not such a bad idea. You might want to read about the Visitor
pattern.

Also, since you've mentioned operator=, explore the necessity to add
a "clone" member function.

I'm open to any ideas. :-)


Why do you need 'operator+' redefined in the implementation class?
Isn't it simply a sum of the coordinates? Aren't the coordinates
known at the base class level?

Anyway, overloading operators is not an easy task for polymorphic
classes. The simplest answer to "how" is "don't". The biggest
problem in this situation is the "slicing" that occurs when you
return an object of the base class. Unfortunately, there is no
cure for slicing. The best thing would be to clone a point and
then use += on it (which returns a reference to the same object):

struct Point {
virtual ~Point() {}
Point* clone() const = 0;
virtual Point& operator +=(Point const&) = 0;
};

struct ParticularPoint : Point {
Point* clone() const {
return new ParticularPoint(*this); // or whatever
}

Point& operator +=(Point const& cp) {
// add coordinates of 'cp' to *this
return *this;
}
};

int main() {
ParticularPoint p1, p2;
Point* pp = p.clone();
*pp += p2;

delete pp;
}

Victor
Jul 19 '05 #2
On 05/11/2003 "Victor Bazarov" <v.********@comAcast.net> wrote:
"Carl Bevil" <ca**************@yahoo.com> wrote...

Hopefully what I'm saying is clear; if not, please let me know. :-)
After reading the rest, yes, you're unclear.


Sorry; that's what I get for coding in a newsreader....

What I'm trying to do is analogous to:

class Point
{


Perhaps you need

public:

here...


Yes, you're correct...
virtual void function(int x) = 0;
}

;

class PointImplemenation


Shouldn't this be

class PointImplementation : public Point
{
virtual void function(int x);
}

;


Yes, correct again. :-)
Anyone have an elegant solution for this problem? I've thought of the
possibility of using a proxy object instead of direct inheritance,

although
that's not so great either, IMO.


That's not such a bad idea. You might want to read about the Visitor
pattern.


Will do.
Also, since you've mentioned operator=, explore the necessity to add
a "clone" member function.

I'm open to any ideas. :-)
Why do you need 'operator+' redefined in the implementation class?
Isn't it simply a sum of the coordinates? Aren't the coordinates
known at the base class level?


No, in this case they are not. I used the Point class as an example, but in
my situation, the data is held by the derived class and is proprietary to the
third-party system I mentioned. The base class is meant only to define an
interface and not hold any data or implement any functionality.
Anyway, overloading operators is not an easy task for polymorphic
classes. The simplest answer to "how" is "don't". The biggest
problem in this situation is the "slicing" that occurs when you
return an object of the base class. Unfortunately, there is no
cure for slicing. The best thing would be to clone a point and
then use += on it (which returns a reference to the same object):

struct Point {
virtual ~Point() {}
Point* clone() const = 0;
virtual Point& operator +=(Point const&) = 0;
};
Should clone be virtual?
struct ParticularPoint : Point {
Point* clone() const {
return new ParticularPoint(*this); // or whatever
}

Point& operator +=(Point const& cp) {
// add coordinates of 'cp' to *this
return *this;
}
};

int main() {
ParticularPoint p1, p2;
Point* pp = p.clone();
*pp += p2;

delete pp;
}


I'm hoping to hide the derived class completely from clients. Thinking about
it more, this would probably require clients to always have pointers to Point
objects. Something like this:

Point* pt = Point::Create();

... and Point::Create() would be a factory which would create a ParticularPoint.

I don't think I like this after all. Perhaps I will use some sort of
proxy-ish object (I'll have a look at the Visitor pattern you mention).

Thanks, this has helped. Sorry about the code mistakes; I need more coffee...

Carl

--
Remove "NOSPAM" to reply in e-mail

Jul 19 '05 #3
"Carl Bevil" <ca**************@yahoo.com> wrote in message
news:Za********************@speakeasy.net...
I'm creating a library for internal use that relies on third-party code. I don't want clients of this library to know anything about the third party
code, when compiling or running. Generally I've been achieving this by having an abstract base class which defines an interface, and inheriting a concrete class which defines the implementation. Clients of the library deal only with the base class and request objects of that type from a factory function.

This works great in most cases. The problems set in when you have operator overloading. For example, I might have a class which defines 2-dimensional point on the screen. I want the user to be able to use operator+, operator==, operator=, etc... on this class.

Hi Car,

The two main C++ approaches to completely hide the implementation details
of a class are:
- Abstract base classes (which what you have going for)
- The pimpl idiom ( a.k.a. the Cheshire cat, and several other names).
When you do not need polymorphic behavior, the second option
is usually to be preferred.

A google search should do, but the basic idea is:
//file: Point.h

class Point {
public:
Point(); // sample constructor...
~Point();
... all public member functions here ...

//next 2 functions must be either implemented or private.
Point(Point const& orig);
Point& operator=(Point const& orig);

private:
struct Impl;
Impl* pimpl_; // as a unique data member
};
//file: Point.cpp

struct Point::Impl {
... put all the data members here ...
... utility functions and constructor if needed ...
};

Point::Point()
: pimpl_( new Impl() )
{
...
}

Point::~Point()
{
delete pimpl_;
}
If your class constructors may throw any exceptions, you should
use a smart pointer (e.g. std::auto_ptr or boost::scoped_ptr)
instead of the naked Impl* data member. This should actually
be the preferred default choice, unless you also want to
avoid exposing a smart-pointer header to your users.
( what I tend to do is put any throwing/complex
operations in the constructor of Point::Impl,
which makes it ok to keep a naked pointer ).

Regards,
Ivan
--
http://ivan.vecerina.com
Jul 19 '05 #4
Hi Ivan and NG,
If your class constructors may throw any exceptions, you should
use a smart pointer (e.g. std::auto_ptr or boost::scoped_ptr)
instead of the naked Impl* data member. This should actually
be the preferred default choice, unless you also want to
avoid exposing a smart-pointer header to your users.


Do you mean here, that I avoid all the pifalls when I throw exceptions
inside classes with pointers (allocating memory) when I just use a smart
pointer? This in fact would be very nice :-).

Coming back to the topic.

Assume my object exists e.g. a Point "p", and I have to pass it to another
class "bar". I could do this via a proxy "bar_proxy". "bar" needs "p" for
quite a long time, and I could not be sure, that "p" still exists, when
"bar" needs it. What means, I need here a kind of "delayed copying", that in
case the Point "p" is destructed, the "bar_proxy" creates an instance.

For a huge amount of Data (1000dim Point ;-) ) I assume that the class Point
itself is smart enough to do this job, what means inside my "bar_proxy" I
just create another "Point pp = p".
For small data-types (double, int,....) I just create a copy as well.

But what shall I do for "medium-sized" data-types ?

struct bar_proxy {
const Point pp; // nice for built-in types and "smart huge types"
// const Point & pp; // nicer, but if p ist destroyed it messes up my
mem.

bar_proxy(const Point& p) : pp(p);
};

Anyway, is this really a proxy or how shall I call it?

Regards,
Patrick
Jul 19 '05 #5
"Patrick Kowalzick" <Pa***************@cern.ch> wrote in message
news:bo**********@sunnews.cern.ch...
| Do you mean here, that I avoid all the pifalls when I throw exceptions
| inside classes with pointers (allocating memory) when I just use a smart
| pointer? This in fact would be very nice :-).
Well, it can help with a lot of the issues. But smart pointers
themselves aren't always trivial to use either...

| Coming back to the topic.
|
| Assume my object exists e.g. a Point "p", and I have to pass it to another
| class "bar". I could do this via a proxy "bar_proxy". "bar" needs "p" for
| quite a long time, and I could not be sure, that "p" still exists, when
| "bar" needs it. What means, I need here a kind of "delayed copying", that
in
| case the Point "p" is destructed, the "bar_proxy" creates an instance.
[...]
There are a few possible approaches.
- first, avoid copies as much as possible by passing objects
by reference when possible.
- the objects themselves may choose to implement some form of
reference counting, with or without automated COW (copy-on-write).
There are many options really.
I would suggest studying Scott Meyer's "(More) Effective C++" books
regarding these topics. You may also read about std::string (which
currently is typically implemented without reference counting,
because it is complex and inefficient in multithreaded apps).
Also, consider using boost::shared_ptr (from www.boost.org)
as a smart pointer for the contained data.

What you really need to chose AFAICT is whether a type will
automatically share its data among object copies or not.
If not, the user is responsible to take care of lifetime issues.
If yes, you need to decide wheter this sharing will be
visible to the users or not (if not, COW needs to be implemented).

| For a huge amount of Data (1000dim Point ;-) ) I assume that the class
Point
| itself is smart enough to do this job, what means inside my "bar_proxy" I
| just create another "Point pp = p".
| For small data-types (double, int,....) I just create a copy as well.
|
| But what shall I do for "medium-sized" data-types ?

There is no general rule about which approach is better.
Testing and tuning is typically required -- as for all optimizations
attempts (avoiding data copies is an optimization...).
Regards,
Ivan
--
http://ivan.vecerina.com
Jul 19 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Google Mike | last post by:
I want to prepare some training for some new employees regarding the topic of multithreaded socket services implemented in PHP. I've been able to implement this with my own design, but I'd like to...
9
by: sk | last post by:
I have an applicaton in which I collect data for different parameters for a set of devices. The data are entered into a single table, each set of name, value pairs time-stamped and associated with...
4
by: Marquisha | last post by:
If this is off-topic, please forgive me. But I thought this might be the perfect spot to get some advice about how to proceed with a project. Working on a Web site design for a nonprofit...
38
by: lawrence | last post by:
I'm just now trying to give my site a character encoding of UTF-8. The site has been built in a hodge-podge way over the last 6 years. The validator tells me I've lots of characters that don't...
2
by: andyjgw | last post by:
Hi I'm a bit new to the designing of custom web page controls and using them in the properties designer window - need a little advice on a concept here. I have two properties in my control -...
12
by: johannblake | last post by:
First off, I am NOT a beginner. I have lots of experience developing professional web sites and am a professional software developer. Unfortunately I've been out of web site development for the...
23
by: JoeC | last post by:
I am a self taught programmer and I have figured out most syntax but desigining my programs is a challenge. I realize that there are many ways to design a program but what are some good rules to...
18
by: bsruth | last post by:
I tried for an hour to find some reference to concrete information on why this particular inheritance implementation is a bad idea, but couldn't. So I'm sorry if this has been answered before....
2
by: marklawford | last post by:
I've been prototyping a reporting solution using XSLT and Java to transform a number of XML files into different formats (PDF and CSV mainly). The XML comes from a legacy system where a number of...
2
by: tatata9999 | last post by:
Currently my site is not using CSS. The thing I want to do with it is, I think, it needs a face lift, otherwise, it may look boring, target audience seems very much into visual stuff, flushy,...
0
by: Aliciasmith | last post by:
In an age dominated by smartphones, having a mobile app for your business is no longer an option; it's a necessity. Whether you're a startup or an established enterprise, finding the right mobile app...
2
by: giovanniandrean | last post by:
The energy model is structured as follows and uses excel sheets to give input data: 1-Utility.py contains all the functions needed to calculate the variables and other minor things (mentions...
4
NeoPa
by: NeoPa | last post by:
Hello everyone. I find myself stuck trying to find the VBA way to get Access to create a PDF of the currently-selected (and open) object (Form or Report). I know it can be done by selecting :...
3
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be using a very simple database which has Form (clsForm) & Report (clsReport) classes that simply handle making the calling Form invisible until the Form, or all...
1
by: Teri B | last post by:
Hi, I have created a sub-form Roles. In my course form the user selects the roles assigned to the course. 0ne-to-many. One course many roles. Then I created a report based on the Course form and...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 1 Nov 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM) Please note that the UK and Europe revert to winter time on...
0
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be focusing on the Report (clsReport) class. This simply handles making the calling Form invisible until all of the Reports opened by it have been closed, when it...
0
isladogs
by: isladogs | last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, Mike...
3
by: GKJR | last post by:
Does anyone have a recommendation to build a standalone application to replace an Access database? I have my bookkeeping software I developed in Access that I would like to make available to other...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.