473,396 Members | 1,789 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

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

Design problem related to A-Bag-Of-Fruit is not the same as A-Bag-Of-Apple

Class hierarchy below demonstrates my problem:

#include <vector>
#include <boost/smart_ptr.hpp>

class Fruit {
public:
virtual ~Fruit() = 0;
};

class Apple : public Fruit {
//...
};

class Banana : public Fruit {
//...
};

class BagOfFruit {
public:
virtual ~BagOfFruit() = 0;

void push_fruit (const Fruit&);

private:
typedef boost::shared_ptr<FruitFruitPtr;
typedef std::vector<FruitPtrFruitVector;
FruitVector itsContents;
};

class BagOfApple : public BagOfFruit {
//...
};

class BagOfBanana : public BagOfFruit {
//...
};

class Shop {
public:
virtual ~Shop() = 0 {}

void push_bag (const BagOfFruit&);

private:
typedef boost::shared_ptr<BagOfFruitBagOfFruitPtr;
typedef std::vector<BagOfFruitPtrBagsVector;
BagsVector itsContents;
};

class AppleShop : public Shop {
//...
};

class BananaShop : public Shop {
//...
};

class Market {
public:
void push_shop (const Shop&);

private:
typedef boost::shared_ptr<ShopShopPtr;
typedef std::vector<ShopPtrShopVector;
ShopVector itsContents;
};

The main thing here is Market class. It has to be able to deal with various
shops. Operating through base class Shop is clearest way to do it. Now,
shops deal with bags of fruit. Thus, I need common interface to various
bags of fruit (namely BagOfFruit class). And bags of fruit operate with
various Fruit subclasses.

Upper design has numerous problems. First of all, working with BagOfFruit
pointer allows Apple to be pushed into BagOfBanana which should not happen.
Same goes with Shop. BagOfApple could end up in BananaShop which should not
happen.

All above just illustrates my real problem. I have two requirements:
- common interface that allows me to manipulate with Fruit, BagOfFruit
and Shop
- restriction (already on base class level) that ie. Apple can't end up
in BagOfBanana etc.

I've had two ideas:
- Use of templates for Fruit, BagOfFruit and Shop. This solves problem
of restricting who goes where because template instantiation like
BagOfFruit<Bananaworks only for Banana and so on... But this eliminates
the possibility for Market to store any kind of Shop because there is no
base Shop class, only Shop<Ttemplate. And the main purpose of all this
was to enable Market to contain and handle any shop...

- Other idea was to use kind of RTTI in base classes. For example I
would add
enum FruitTypes {
APPLE,
BANANA
};

and then to all base classes:

virtual FruitTypes FruitType() const = 0;

With this, Fruit::operator= (const Fruit& rv) (again, for demonstration
purpose let's assume that this operator is overloaded) would throw if
'this' and 'rv' don't return same FruitType(). This seems like behavior
that could confuse clients, and would also require same thing done for
other base classes, many checks in member methods and so on... Code getting
messy, and behavior confusing, this is never good. But I can't figure out
anything else to do... Any suggestions?

TIA
Dec 2 '06 #1
7 2309

T.A. wrote:
Class hierarchy below demonstrates my problem:

#include <vector>
#include <boost/smart_ptr.hpp>

class Fruit {
public:
virtual ~Fruit() = 0;
};

class Apple : public Fruit {
//...
};

class Banana : public Fruit {
//...
};

class BagOfFruit {
public:
virtual ~BagOfFruit() = 0;

void push_fruit (const Fruit&);

private:
typedef boost::shared_ptr<FruitFruitPtr;
typedef std::vector<FruitPtrFruitVector;
FruitVector itsContents;
};

class BagOfApple : public BagOfFruit {
//...
};

class BagOfBanana : public BagOfFruit {
//...
};

class Shop {
public:
virtual ~Shop() = 0 {}

void push_bag (const BagOfFruit&);

private:
typedef boost::shared_ptr<BagOfFruitBagOfFruitPtr;
typedef std::vector<BagOfFruitPtrBagsVector;
BagsVector itsContents;
};

class AppleShop : public Shop {
//...
};

class BananaShop : public Shop {
//...
};

class Market {
public:
void push_shop (const Shop&);

private:
typedef boost::shared_ptr<ShopShopPtr;
typedef std::vector<ShopPtrShopVector;
ShopVector itsContents;
};

The main thing here is Market class. It has to be able to deal with various
shops. Operating through base class Shop is clearest way to do it. Now,
shops deal with bags of fruit. Thus, I need common interface to various
bags of fruit (namely BagOfFruit class). And bags of fruit operate with
various Fruit subclasses.
Shops deal with bags. A bag can be a bag of apples or a bag of bananas,
etc.
A Shop can sell any of those fruit bag derivatives.
So template the containers.

t#include <iostream>
#include <vector>

struct Fruit {
virtual ~Fruit() = 0;
};

Fruit::~Fruit() { }

struct Apple : public Fruit {
Apple() { std::cout << "Apple()\n"; }
Apple(const Apple& copy) { std::cout << "copy Apple\n"; }
~Apple() { std::cout << "~Apple()\n"; }
};

template < typename F >
class BagOfFruit {
std::vector< F vf;
public:
BagOfFruit() : vf() { }
BagOfFruit(size_t sz) : vf(sz) { }
void push_back( const F& r_f)
{
vf.push_back(r_f);
}
};

int main() {
BagOfFruit< Apple apples(10);
}

I'm sorry, i don't see any benefit of using a smart ptr when storing
fruit.
>
Upper design has numerous problems. First of all, working with BagOfFruit
pointer allows Apple to be pushed into BagOfBanana which should not happen.
Same goes with Shop. BagOfApple could end up in BananaShop which should not
happen.

All above just illustrates my real problem. I have two requirements:
- common interface that allows me to manipulate with Fruit, BagOfFruit
and Shop
- restriction (already on base class level) that ie. Apple can't end up
in BagOfBanana etc.

I've had two ideas:
- Use of templates for Fruit, BagOfFruit and Shop. This solves problem
of restricting who goes where because template instantiation like
BagOfFruit<Bananaworks only for Banana and so on... But this eliminates
the possibility for Market to store any kind of Shop because there is no
base Shop class, only Shop<Ttemplate. And the main purpose of all this
was to enable Market to contain and handle any shop...
Why, can't a Shop hold a vector of templated bags?
>
- Other idea was to use kind of RTTI in base classes. For example I
would add
enum FruitTypes {
APPLE,
BANANA
};

and then to all base classes:

virtual FruitTypes FruitType() const = 0;

With this, Fruit::operator= (const Fruit& rv) (again, for demonstration
purpose let's assume that this operator is overloaded) would throw if
'this' and 'rv' don't return same FruitType(). This seems like behavior
that could confuse clients, and would also require same thing done for
other base classes, many checks in member methods and so on... Code getting
messy, and behavior confusing, this is never good. But I can't figure out
anything else to do... Any suggestions?

TIA
Dec 3 '06 #2

T.A. wrote:
Class hierarchy below demonstrates my problem:

#include <vector>
#include <boost/smart_ptr.hpp>

class Fruit {
public:
virtual ~Fruit() = 0;
};

class Apple : public Fruit {
//...
};

class Banana : public Fruit {
//...
};

class BagOfFruit {
public:
virtual ~BagOfFruit() = 0;

void push_fruit (const Fruit&);

private:
typedef boost::shared_ptr<FruitFruitPtr;
typedef std::vector<FruitPtrFruitVector;
FruitVector itsContents;
};

class BagOfApple : public BagOfFruit {
//...
};

class BagOfBanana : public BagOfFruit {
//...
};

class Shop {
public:
virtual ~Shop() = 0 {}

void push_bag (const BagOfFruit&);

private:
typedef boost::shared_ptr<BagOfFruitBagOfFruitPtr;
typedef std::vector<BagOfFruitPtrBagsVector;
BagsVector itsContents;
};

class AppleShop : public Shop {
//...
};

class BananaShop : public Shop {
//...
};

class Market {
public:
void push_shop (const Shop&);

private:
typedef boost::shared_ptr<ShopShopPtr;
typedef std::vector<ShopPtrShopVector;
ShopVector itsContents;
};

The main thing here is Market class. It has to be able to deal with various
shops. Operating through base class Shop is clearest way to do it. Now,
shops deal with bags of fruit. Thus, I need common interface to various
bags of fruit (namely BagOfFruit class). And bags of fruit operate with
various Fruit subclasses.

Upper design has numerous problems. First of all, working with BagOfFruit
pointer allows Apple to be pushed into BagOfBanana which should not happen.
Same goes with Shop. BagOfApple could end up in BananaShop which should not
happen.

All above just illustrates my real problem. I have two requirements:
- common interface that allows me to manipulate with Fruit, BagOfFruit
and Shop
- restriction (already on base class level) that ie. Apple can't end up
in BagOfBanana etc.

I've had two ideas:
- Use of templates for Fruit, BagOfFruit and Shop. This solves problem
of restricting who goes where because template instantiation like
BagOfFruit<Bananaworks only for Banana and so on... But this eliminates
the possibility for Market to store any kind of Shop because there is no
base Shop class, only Shop<Ttemplate. And the main purpose of all this
was to enable Market to contain and handle any shop...

- Other idea was to use kind of RTTI in base classes. For example I
would add
enum FruitTypes {
APPLE,
BANANA
};

and then to all base classes:

virtual FruitTypes FruitType() const = 0;

With this, Fruit::operator= (const Fruit& rv) (again, for demonstration
purpose let's assume that this operator is overloaded) would throw if
'this' and 'rv' don't return same FruitType(). This seems like behavior
that could confuse clients, and would also require same thing done for
other base classes, many checks in member methods and so on... Code getting
messy, and behavior confusing, this is never good. But I can't figure out
anything else to do... Any suggestions?

TIA

Let's do this.

class AbstractBagOfFruit {
public:
virtual ~AbstractBagOfFruit() = 0;
virtual void push_fruit(const Fruit &);
}

template<class Fruit>
class BagOfFruit : public AbstractBagOfFruit {
public:
virtual ~BagOfFruit();

void push_fruit (const Fruit&);

private:
typedef boost::shared_ptr<FruitFruitPtr;
typedef std::vector<FruitPtrFruitVector;
FruitVector itsContents;
};

There are many types of bag when you *analyze*. And then you need to
implement the model you just get. Use a template is just a *implement*
tech. I don't think this is a same thing.

Good Luck.

Dec 3 '06 #3
* T.A.:
Class hierarchy below demonstrates my problem:
[snip]

Too much for me to read, sorry.

But in general, note that a /constant/ BagOfApple is-a constant BagOfFruit.

There.

--
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?
Dec 3 '06 #4
On 2 Dec 2006 17:56:16 -0800, Salt_Peter wrote:
T.A. wrote:
>Class hierarchy below demonstrates my problem:

#include <vector>
#include <boost/smart_ptr.hpp>

class Fruit {
public:
virtual ~Fruit() = 0;
};

class Apple : public Fruit {
//...
};

class Banana : public Fruit {
//...
};

class BagOfFruit {
public:
virtual ~BagOfFruit() = 0;

void push_fruit (const Fruit&);

private:
typedef boost::shared_ptr<FruitFruitPtr;
typedef std::vector<FruitPtrFruitVector;
FruitVector itsContents;
};

class BagOfApple : public BagOfFruit {
//...
};

class BagOfBanana : public BagOfFruit {
//...
};

class Shop {
public:
virtual ~Shop() = 0 {}

void push_bag (const BagOfFruit&);

private:
typedef boost::shared_ptr<BagOfFruitBagOfFruitPtr;
typedef std::vector<BagOfFruitPtrBagsVector;
BagsVector itsContents;
};

class AppleShop : public Shop {
//...
};

class BananaShop : public Shop {
//...
};

class Market {
public:
void push_shop (const Shop&);

private:
typedef boost::shared_ptr<ShopShopPtr;
typedef std::vector<ShopPtrShopVector;
ShopVector itsContents;
};

The main thing here is Market class. It has to be able to deal with various
shops. Operating through base class Shop is clearest way to do it. Now,
shops deal with bags of fruit. Thus, I need common interface to various
bags of fruit (namely BagOfFruit class). And bags of fruit operate with
various Fruit subclasses.

Shops deal with bags. A bag can be a bag of apples or a bag of bananas,
etc.
A Shop can sell any of those fruit bag derivatives.
So template the containers.

t#include <iostream>
#include <vector>

struct Fruit {
virtual ~Fruit() = 0;
};

Fruit::~Fruit() { }

struct Apple : public Fruit {
Apple() { std::cout << "Apple()\n"; }
Apple(const Apple& copy) { std::cout << "copy Apple\n"; }
~Apple() { std::cout << "~Apple()\n"; }
};

template < typename F >
class BagOfFruit {
std::vector< F vf;
public:
BagOfFruit() : vf() { }
BagOfFruit(size_t sz) : vf(sz) { }
void push_back( const F& r_f)
{
vf.push_back(r_f);
}
};

int main() {
BagOfFruit< Apple apples(10);
}

I'm sorry, i don't see any benefit of using a smart ptr when storing
fruit.
>>
Upper design has numerous problems. First of all, working with BagOfFruit
pointer allows Apple to be pushed into BagOfBanana which should not happen.
Same goes with Shop. BagOfApple could end up in BananaShop which should not
happen.

All above just illustrates my real problem. I have two requirements:
- common interface that allows me to manipulate with Fruit, BagOfFruit
and Shop
- restriction (already on base class level) that ie. Apple can't end up
in BagOfBanana etc.

I've had two ideas:
- Use of templates for Fruit, BagOfFruit and Shop. This solves problem
of restricting who goes where because template instantiation like
BagOfFruit<Bananaworks only for Banana and so on... But this eliminates
the possibility for Market to store any kind of Shop because there is no
base Shop class, only Shop<Ttemplate. And the main purpose of all this
was to enable Market to contain and handle any shop...

Why, can't a Shop hold a vector of templated bags?
Because Market needs to operate shops through base class pointers. If Shop
holds templatized BagOfFruit then it also must be implemented as template:

template <class bag_of_fruit>
class Shop
{
public:
//...
private:
std::vector<bag_of_fruit>
};

This allows shop to be restricted to specific BagOfFruit but disallows
Market to hold any type of Shop because there is no base class Shop and
thus I can't store Shop pointers in Market. Storing pointers to Shop is
only way I know for Market to operate on Shop polymorphically.
Dec 3 '06 #5
On 2 Dec 2006 19:35:43 -0800, Xeranic wrote:
T.A. wrote:
>Class hierarchy below demonstrates my problem:

...

TIA

Let's do this.

class AbstractBagOfFruit {
public:
virtual ~AbstractBagOfFruit() = 0;
virtual void push_fruit(const Fruit &);
}

template<class Fruit>
class BagOfFruit : public AbstractBagOfFruit {
public:
virtual ~BagOfFruit();

void push_fruit (const Fruit&);

private:
typedef boost::shared_ptr<FruitFruitPtr;
typedef std::vector<FruitPtrFruitVector;
FruitVector itsContents;
};
On a first glance this looks like the thing I've needed, I'll try it...
Thanks.
>
There are many types of bag when you *analyze*. And then you need to
implement the model you just get. Use a template is just a *implement*
tech. I don't think this is a same thing.
Agreed...
Dec 3 '06 #6
On Sun, 3 Dec 2006 11:22:40 +0100, T.A. wrote:
On 2 Dec 2006 19:35:43 -0800, Xeranic wrote:
>T.A. wrote:
>>Class hierarchy below demonstrates my problem:

...

TIA

Let's do this.

class AbstractBagOfFruit {
public:
virtual ~AbstractBagOfFruit() = 0;
virtual void push_fruit(const Fruit &);
}

template<class Fruit>
class BagOfFruit : public AbstractBagOfFruit {
public:
virtual ~BagOfFruit();

void push_fruit (const Fruit&);

private:
typedef boost::shared_ptr<FruitFruitPtr;
typedef std::vector<FruitPtrFruitVector;
FruitVector itsContents;
};

On a first glance this looks like the thing I've needed, I'll try it...
Thanks.
But on the second glance... It should be sth like this...

class AbstractBagOfFruit {
public:
virtual ~AbstractBagOfFruit() = 0;
virtual void push_fruit(const Fruit &) = 0;
};

template<class FruitType>
class BagOfFruit : public AbstractBagOfFruit {
public:
virtual ~BagOfFruit() {}

virtual void push_fruit (const FruitType& rv);

private:
typedef std::vector<FruitTypeFruitVector;
FruitVector itsContents;
};

typedef BagOfFruit<AppleBagOfApple;

int main ()
{
BagOfApple apple_bag;
}

But this doesn't compile because

void push_fruit(const Fruit &)

is not the same as

void push_fruit(const Apple &)

Pure virtual in AbstractBagOfFruit is not actually implemented in
template<class FruitTypeclass BagOfFruit...

Now, I could use RTTI in push_fruit implementation like this:

template<class FruitType>
void BagOfFruit::push_fruit(const Fruit & rv) {
if (typeid(rv) == typeid (FruitType)) {
// do push
} else {
// throw something
}
}

This not only that is not nice to client of BagOfFruit but also still
allows this to compile:

int main ()
{
BagOfApple apple_bag;

apple_bag.push_fruit (Banana());
}

So I'm stuck at the begining...
Dec 3 '06 #7
"T.A." <to*************@gmail.comwrote:
Class hierarchy below demonstrates my problem:

#include <vector>
#include <boost/smart_ptr.hpp>

class Fruit {
public:
virtual ~Fruit() = 0;
};

class Apple : public Fruit {
//...
};

class Banana : public Fruit {
//...
};

class BagOfFruit {
public:
virtual ~BagOfFruit() = 0;

void push_fruit (const Fruit&);

private:
typedef boost::shared_ptr<FruitFruitPtr;
typedef std::vector<FruitPtrFruitVector;
FruitVector itsContents;
};

class BagOfApple : public BagOfFruit {
//...
};

class BagOfBanana : public BagOfFruit {
//...
};

class Shop {
public:
virtual ~Shop() = 0 {}

void push_bag (const BagOfFruit&);

private:
typedef boost::shared_ptr<BagOfFruitBagOfFruitPtr;
typedef std::vector<BagOfFruitPtrBagsVector;
BagsVector itsContents;
};

class AppleShop : public Shop {
//...
};

class BananaShop : public Shop {
//...
};

class Market {
public:
void push_shop (const Shop&);

private:
typedef boost::shared_ptr<ShopShopPtr;
typedef std::vector<ShopPtrShopVector;
ShopVector itsContents;
};

The main thing here is Market class. It has to be able to deal with various
shops. Operating through base class Shop is clearest way to do it. Now,
shops deal with bags of fruit. Thus, I need common interface to various
bags of fruit (namely BagOfFruit class). And bags of fruit operate with
various Fruit subclasses.
Let's look at a real world example. Let's say my name is "market" and
your name is "appleShop". You like it when people give you bags of
apples. Is it appropriate for me to deal with you without knowing that
fact? Of course not.

Market simply cannot pass "bags of fruit" to Shops without knowing (a)
what kind of fruit is in the bag and (b) what kind of fruit the shop
wants.

In other words, your whole design is messed up. "push_bag(BagOfFruit)"
is an inappropriate member-function for "Shop", remove it and Markets
can work with Shops with no problem. (Or as another poster said, allow
Markets to only work with 'const Shop' objects.
Upper design has numerous problems. First of all, working with BagOfFruit
pointer allows Apple to be pushed into BagOfBanana which should not happen.
Personally I don't see a problem with that. Although it may be true that
an AppleShop object can't have Banana objects in its particular bag of
fruit, that doesn't mean that you can't have a generic BagOfFruit class.
For example:

class AppleShop {
BagOfFruit bag;
public:
void push_apple( const Apple& a );
};

There is nothing wrong with the above, the AppleShop class is in charge
of making sure that only Apples are put in its Bag.
All above just illustrates my real problem. I have two requirements:
- common interface that allows me to manipulate with Fruit, BagOfFruit
and Shop
- restriction (already on base class level) that ie. Apple can't end up
in BagOfBanana etc.
You can have a common interface, but not the interface you have
currently. You should only have methods that actually *are* common
amongst the various sub-classes.
I've had two ideas:
I don't like either of your ideas. What you need to do is identify what
methods Market actually uses of Shop ("push_bag" is obviously not one of
them because Market doesn't have enough information to do that,) and
then make an abstract class containing only those methods.

Do the same for what methods Shop uses when dealing with BagOfFruit
objects.

--
To send me email, put "sheltie" in the subject.
Dec 3 '06 #8

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

Similar topics

9
by: Patchwork | last post by:
Hi Everyone, I have a design related question (in C++) that I am hoping someone can help me with. It is related to my previous post but since it was pointed out that I was more or less asking...
22
by: Nunaya | last post by:
We have developed two objects called "customer" and "salesrep". For simplicity, assume that these two objects will talk directly to a database. The database has three tables: customers,...
2
by: LRS Kumar | last post by:
In Section 1.4 of Alexandrescu's Modern C++ Design, he states the following: <quote> 1. You cannot specialize structure. Using templates alone you cannot specialize the structure of a class...
0
by: devont | last post by:
Hello all, I dont think this is off topic because it is C related, more specifically C function() design related. I need to implement a BytesPerSecond() function, but don't really know how to...
0
by: JKJ | last post by:
I'm not an OOP guru, but I would say ". . .not necessarily" What if the base class and derived classes are internal? Then the base class has to be within the same assembly to be inherited from. ...
1
by: Nogusta123 | last post by:
Hi, I have had a lot of problems getting web pages, master pages and content pages to render in VS2005 design view the same as they would in Internet Explorer. I did a lot of looking on the...
2
by: Water Cooler v2 | last post by:
I want my application to do three tasks simultaneously. Each of the three tasks must be performed at a periodic interval of time. Each of the three tasks is somewhat complicated and is thus...
5
by: jehugaleahsa | last post by:
Hello: What is the point of using a DataTable in ASP .NET? We are unsure how you can use them without 1) rebuilding them every postback, or 2) taking up precious memory. We are not sure how to...
2
by: existential.philosophy | last post by:
This is a new problem for me: I have some queries that open very slowly in design view. My benchmark query takes about 20 minutes to open in design view. That same query takes about 20 minutes...
0
by: cynthiasolc | last post by:
Hi, I'm writing a C# Forms application where 40+ users will be viewing a PDF file stored on a secure folder on another server. There could be more than one user accessing the PDF file. In...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

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.