By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,943 Members | 1,260 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,943 IT Pros & Developers. It's quick & easy.

specialized containment???

P: n/a
Hello, maybe somebody can enlighten me? :)
I wasn't really sure how to concisely describe the following scenario
so it was tricky to search for help.
Simplifying the problem...
I have a home which contains people. I also want a SpecialHome which
has to contain a set of SpecialPersons.
class Home {
Person* getPerson(id);

vector<Person*> m_People;
}

class SpecialHome : public CHome {
SpecialPerson* getPerson(id);
vector<SpecialPerson*> m_People;
}
So obviously the above SpecialHome class isn't how I would want to
implement this. There's nothing being inherited, the list of pointers
are unnecessarily duplicated, etc. The problem is that a number of
Home methods accept and return Persons. In my more complicated
situation, I really want to avoid a templatized Home class (it would
make for quite a confusing class diagram). I guess accepting Persons
isn't such a problem thanks to polymorphism, but returning them is
(I've also got a Person iterator class in an effort to abstract away
the containment mechanism in Home).

The approach I've tried taking is to remove all of these Person-related
methods from Home and put them is a sort of templatized "manipulator"
class. This manipulator was made a friend of Home and SpecialHome so
it more or less can do whatever it pleases. Naturally, there's a lot
of dynamic_casting since the vector lives in the base class (for some
reason dynamic_casting always makes me uncomfortable).

I'm having trouble getting this to compile because of complications
with the more convoluted scenario I'm dealing with.
This lead me to take a step back and ask myself if there isn't a better
way to do design the class structure. I would imagine the scenario I
described above is a fairly common one.

Any tips are greatly appreciated!
cheers!

Nov 22 '05 #1
Share this Question
Share on Google+
3 Replies


P: n/a
* Mr Dyl:

I have a home which contains people. I also want a SpecialHome which
has to contain a set of SpecialPersons.
class Home {
Person* getPerson(id);

vector<Person*> m_People;
}

class SpecialHome : public CHome {
SpecialPerson* getPerson(id);
vector<SpecialPerson*> m_People;
}


That sketch isn't really enough to go on, because you haven't indicated
access, and for this kind of problem what's private and what's public
and what's const or not is key.

Here's a more fleshed-out sketch that illustrates the fundamental
problem you're up against:

class Person {};
class ShortPerson: public Person {};
class LongPerson: public Person {};

class Home
{
public:
addPerson( Person* );
std::vector<Person const*> persons() const;
};

class ShortPersonHome: public Home
public:
addPerson( ShortPerson* );
std::vector<ShortPerson const*> persons() const;
};

class LongPersonHome: public Home
public:
addPerson( LongPerson* );
std::vector<LongPerson const*> persons() const;
};

int main()
{
ShortPersonHome home;
Home* pHome = &home;
LongPerson longPerson;

pHome->addPerson( &longPerson ); // Oops, roof is too low!
}

As you can see it's a problem of mutability, not of downcasting the
internal representation (although that's also a problem, but managable).

What you need is something like

// Home
// MutableHome
// ShortPersonHome
// MutableShortPersonHome
// LongPersonHome
// MutableLongPersonHome

class Home
{
public:
std::vector<Person const*> persons() const;
};

class MutableHome: public Home
{
public:
addPerson( Person* );
};

class ShortPersonHome: public Home
public:
std::vector<ShortPerson const*> persons() const;
};

class MutableShortPersonHome: public ShortPersonHome
{
public:
addPerson( ShortPerson* );
};

class LongPersonHome: public Home
{
public:
std::vector<LongPerson const*> persons() const;
};

class MutableLongPersonHome: public LongPersonHome
{
public:
addPerson( LongPerson* );
};

Now in ShortPersonHome you can safely assume that any Person in there is
really a ShortPerson, because no other kinds of persons can be added.
So you can simply provide an internal accessor function that downcasts.
As I wrote, that part is a managable problem, also with other solutions:
note that C++ does support covariance for function results.

Hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Nov 22 '05 #2

P: n/a
Hey Alf,
thanks for the reply.
Interesting. At the moment I'd only been thinking about the
relationship between parent and child classes so I hadn't even been
thinking about the problem you pointed out.

A question though,

Home contains (I assume) a list of persons accessed through:

std::vector<Person const*> persons() const

LongPersonHome also provides access to this list (but they are
LongPersons now):

std::vector<LongPerson const*> persons() const;

How are you able to cast a std::vector<Person const*> to
std::vector<LongPerson const*>?
I think maybe there's something fundamental here that I'm not seeing.
Thanks again!
Dylan

Nov 22 '05 #3

P: n/a
* Mr Dyl:

Home contains (I assume) a list of persons accessed through:

std::vector<Person const*> persons() const

LongPersonHome also provides access to this list (but they are
LongPersons now):

std::vector<LongPerson const*> persons() const;

How are you able to cast a std::vector<Person const*> to
std::vector<LongPerson const*>?
Note that the signature of 'persons' specifies a copy.

A mutable collection of T isn't really convertible along with the type
of T. That's a problem with Java arrays, for example, where Java is
reduced to run-time type-checking, throwing an exception if the type of
an element assigned to an array is of the wrong dynamic type,
<url:
http://java.sun.com/docs/books/jls/third_edition/html/arrays.html#10.10>,
which implies a run-time check of every assignment to a Java array.

Note that that this concerns an array casted analogous to casting
std::vector<LongPerson const*> to std::vector<Person const*>, an upcast,
which is opposite and many might think safer than the cast you mention.

So, let 'persons' create a _copy_... ;-)

Or, its return type is non-mutable collection, of a collection type that
supports this kind of thing; that means essentially, a collection type
you have defined.

Or, represent it by a collection of member functions that provide
iteration.

Or, represent it by a general standard-library compatible iterator.

I think maybe there's something fundamental here that I'm not seeing.


Yes, you're now up against the idea of "virtual data".

<url:
http://www.parashift.com/c++-faq-lite/value-vs-ref-semantics.html#faq-31.2>.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Nov 22 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.