Subset of derived classes accessing base class functions

F

fgh.vbn.rty

Say I have a base class B and four derived classes d1, d2, d3, d4. I
have three functions fx, fy, fz such that:
fx should only be called by d1, d2
fy should only be called by d2, d3
fz should only be called by d1, d3, d4

I think I have two options.
(1) Make all functions virtual and define them in the required derived
classes. This will of course lead to a lot of code duplication and
problems in maintainability.
(2) Keep the functions in the base class. Define some type of
identifier (ex: a string) for each of the derived classes and add some
checks at the top of each fx, fy, fz to ensure that only the
appropriate di's are accessing them.

I have implemented (2) but I'm not happy with it because I don't seem
to use the identifier for anything else. Is it possible to use
something like typeid instead for the same purpose?

Is there any other alternate way to do something like this? May be a
design pattern that can be adapted to handle such a situation?
 
D

Darío Griffo

Say I have a base class B and four derived classes d1, d2, d3, d4. I
have three functions fx, fy, fz such that:
fx should only be called by d1, d2
fy should only be called by d2, d3
fz should only be called by d1, d3, d4
Is there any other alternate way to do something like this? May be a
design pattern that can be adapted to handle such a situation?

Maybe inserting another hierarchy level an multiple hierarchy:

class B{
//all common thing
virtual ~B();
}

class FXToImplement: public B
{
virtual void fx();
virtual ~FXToImplement()=0;
}

class FYToImplement: public B
{
virtual void fy();
virtual ~FYToImplement()=0;
}

class FZToImplement: public B
{
virtual void fz();
virtual ~FZToImplement()=0;
}

class d1: public FXToImplement,FZToImplement
{
void fx();
void fz();
}

and you can continue with the others
 
J

James Kanze

Say I have a base class B and four derived classes d1, d2, d3, d4. I
have three functions fx, fy, fz such that:
fx should only be called by d1, d2
fy should only be called by d2, d3
fz should only be called by d1, d3, d4

Then you have a fundamental design problem. Something is wrong
with this scenario. The base class doesn't know about the
derived classes, so it can't impose any restrictions on a subset
of them. And if the restriction comes from the derived class
itself, then the class knows about it, and will conform to it.

[...]
Is there any other alternate way to do something like this?
May be a design pattern that can be adapted to handle such a
situation?

Perhaps you'd best describe the problem you're trying to solve,
and not just the solution which doesn't work.
 
F

fgh.vbn.rty

James said:
Say I have a base class B and four derived classes d1, d2, d3, d4. I
have three functions fx, fy, fz such that:
fx should only be called by d1, d2
fy should only be called by d2, d3
fz should only be called by d1, d3, d4

Then you have a fundamental design problem. Something is wrong
with this scenario. The base class doesn't know about the
derived classes, so it can't impose any restrictions on a subset
of them. And if the restriction comes from the derived class
itself, then the class knows about it, and will conform to it.

[...]
Is there any other alternate way to do something like this?
May be a design pattern that can be adapted to handle such a
situation?

Perhaps you'd best describe the problem you're trying to solve,
and not just the solution which doesn't work.

--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orient�e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34

Perhaps you are right :-(. Let me write out the problem in better
terms.

Say I have a base class called Car.
I have four different cars Car1, Car2, Car3, Car4.
There are three types of tyres TyreX, TyreY, TyreZ.
TyreX can only "be applied to" Car1, Car2.
TyreY only to Car2, Car3.
TyreZ only to Car1, Car3, Car4.

As the previous poster suggested I could possibly first have derived
classes CarWithTyreX, CarWithTyreY, CarWithTyreZ. And then Car1 is
derived from CarWithTyreX, CarWithTyreZ etc.,

But the problem with that approach is that the Car has many other
features (engine, windows etc.,). And I definitely shouldn't be doing
derived classes like CarWithTyreXEngineE1..... That's why I was
thinking of just deriving Car1, ... Car4 directly from Car and then
applying all other functions appropriately.

Also, note that the features aren't just "building blocks" as such.
They can be just functions that modify the object's properties in some
way.

Is there a mistake in this approach?
 
M

Marcel Müller

Hi,

Darío Griffo said:
class FXToImplement: public B

probably you meant

class FXToImplement: virtual public B

otherwise you have multiple instances of B in your derived class.


Marcel
 
M

Marcel Müller

Hi!

Perhaps you are right :-(. Let me write out the problem in better
terms.
[...]

you wrote exactly the same except that you changed the class and method
names.

We still don't know where the dependency of some methodes to the derived
classes come from. Why must they no be called for some derived classes?
What happens in that case?

As the previous poster suggested I could possibly first have derived
classes CarWithTyreX, CarWithTyreY, CarWithTyreZ. And then Car1 is
derived from CarWithTyreX, CarWithTyreZ etc.,
But the problem with that approach is that the Car has many other
features (engine, windows etc.,). And I definitely shouldn't be doing
derived classes like CarWithTyreXEngineE1..... That's why I was
thinking of just deriving Car1, ... Car4 directly from Car and then
applying all other functions appropriately.

? - nobody prevents you from implementing the common features in the
virtual baseclass Car.

Also, note that the features aren't just "building blocks" as such.
They can be just functions that modify the object's properties in some
way.

That makes no difference in any way.


Marcel
 
F

fgh.vbn.rty

Marcel said:
Hi!

Perhaps you are right :-(. Let me write out the problem in better
terms.
[...]

you wrote exactly the same except that you changed the class and method
names.

We still don't know where the dependency of some methodes to the derived
classes come from. Why must they no be called for some derived classes?
What happens in that case?

Well, what I was trying to convey was that a certain type of car can
only be fitted with a certain type of Tyre. For instance, Car1 is
compatible only with TyreX and TyreZ. If it attempts to be fitted with
TyreY then we can of course print a warning and/or throw an
exception.

I was wondering if there is a way to entirely prevent Car1 from having
a way to call the TyreY function. Sorry if I'm being unclear.

Thanks.
 
M

Marcel Müller

Well, what I was trying to convey was that a certain type of car can
only be fitted with a certain type of Tyre. For instance, Car1 is
compatible only with TyreX and TyreZ.

Of course, but neither your class is a car nor it have tyres. The
explanatory power of the paradigm ends here.
If it attempts to be fitted with
TyreY then we can of course print a warning and/or throw an
exception.

This is no problem. You can easily check this at runtime by overloading
some of your funtions in some of the derived classes with an empty stub
that only throws some not_supported_exception.
I was wondering if there is a way to entirely prevent Car1 from having
a way to call the TyreY function. Sorry if I'm being unclear.

If you want to check for this at compile time, the compatibility matrix
has to be part of your class tree. Dario told you how to implement this.


Marcel
 
J

James Kanze

James said:
Say I have a base class B and four derived classes d1, d2, d3, d4. I
have three functions fx, fy, fz such that:
fx should only be called by d1, d2
fy should only be called by d2, d3
fz should only be called by d1, d3, d4
Then you have a fundamental design problem. Something is
wrong with this scenario. The base class doesn't know about
the derived classes, so it can't impose any restrictions on
a subset of them. And if the restriction comes from the
derived class itself, then the class knows about it, and
will conform to it.
[...]
Is there any other alternate way to do something like
this? May be a design pattern that can be adapted to
handle such a situation?
Perhaps you'd best describe the problem you're trying to
solve, and not just the solution which doesn't work.

Perhaps you are right :-(. Let me write out the problem in
better terms.
Say I have a base class called Car.
I have four different cars Car1, Car2, Car3, Car4.
There are three types of tyres TyreX, TyreY, TyreZ.
TyreX can only "be applied to" Car1, Car2.
TyreY only to Car2, Car3.
TyreZ only to Car1, Car3, Car4.

The first question is: why won't all of the tire types work with
all of the car types? Since you've used suggestive names from a
domain I vaguely know (I own a car), I can guess: each car has a
certain number of constraints concerning the tires it can use
(size being the most obvious one).

You can solve this either at runtime or through the type system.
Normally, static verification (type errors) are to be preferred
to run-time errors, but think about it for awhile: suppose your
code has a pointer to a Car, and you want to apply some Tire* to
it. Given that you don't know the actual type of either Car or
Tire until runtime, how can the compiler tell whether there is a
mismatch or not.

The usual solution here is to provide a virtual function in Car,
which returns the size, etc. (or a list of the sizes, etc.)
which it can accept for Tire. And of course, a function in Tire
which returns its size, etc. Which means a runtime check. But
again, this more or less corresponds to reality: if you go to buy
tires for your car, you won't go to a tire shop specialized in
selling only tires for that particular make and model of car;
you'll go to a general tire shop, pick out a set of tires, and
then check whether they meet the constraints given in your
owners manual (a runtime check).

Note that there can be exceptions: if you can provide a compile
time check, by all means do so. But this generally means
defining additional interfaces, derived from Car and Tire (e.g.
F1RacingCar, F1RacingTires). At that point, code which knows
it's dealing with F1RacingCars and F1RacingTires can get the
compile time check, and avoid the runtime one. (But such code
won't use the basic Car/Tire interface, but rather the derived
interface.)
 

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
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top