T
T.A.
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<Fruit> FruitPtr;
typedef std::vector<FruitPtr> FruitVector;
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<BagOfFruit> BagOfFruitPtr;
typedef std::vector<BagOfFruitPtr> BagsVector;
BagsVector itsContents;
};
class AppleShop : public Shop {
//...
};
class BananaShop : public Shop {
//...
};
class Market {
public:
void push_shop (const Shop&);
private:
typedef boost::shared_ptr<Shop> ShopPtr;
typedef std::vector<ShopPtr> ShopVector;
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<Banana> works 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<T> template. 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:perator= (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
#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<Fruit> FruitPtr;
typedef std::vector<FruitPtr> FruitVector;
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<BagOfFruit> BagOfFruitPtr;
typedef std::vector<BagOfFruitPtr> BagsVector;
BagsVector itsContents;
};
class AppleShop : public Shop {
//...
};
class BananaShop : public Shop {
//...
};
class Market {
public:
void push_shop (const Shop&);
private:
typedef boost::shared_ptr<Shop> ShopPtr;
typedef std::vector<ShopPtr> ShopVector;
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<Banana> works 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<T> template. 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:perator= (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