"BillyO" <Bi********@cali.com> wrote in message
news:jb********************************@4ax.com...
I need a general mechanism for passing parameters to an API function I
am designing, call it foo. Foo processes data, the operation used to
process the data and the parameters for that operation are to be
passed to foo. A simple approach involves the use of base and derived
classes:
Class DataProcessor
{
Public:
enum ProcessorTypeEnum{op1, op2, op3}
DataProcessor(ProcessorTypeEnum
ProcType):m_ProcType(ProcType){}
ProcessorTypeEnum m_ProcType;
}
Class DataProcessorOp1
{
Public:
DataProcessorOp1(int Param1):m_Param1(Param1),
DataProcessor(op1){}
Int m_Param1;
}
And foo:
Foo(const DataProcessor& dp)
{
If (dp.m_ProcType==op1)
{
// cast dp to DataProcessorOp1 and continue
}
Else if (....=op2)
{
Etc
}
}
This is extensible since I can add new derived classes which contain
the necessary parameters as class members.
Not really because extending the class hierarchy with another DataProcessor
class means that both the base class and the Foo() function need to be
modified. Generally you want to avoid this, especially with API functions.
An alternate approach is to make DataProcessor polymorphic and use
RTTI to distinguish between dynamic types in Foo. I think the two are
equivalent in terms of storage, but what are the pros and cons of
both? Or is their a better way entirely?
Difficult to say what is best without more context. For example in which way
are the DataProcessor classes different? Do they share a common interface?
To me, your enum idea does not look like a good idea for the reasons stated
above. There may be a good reason resort to enums and using casts, but I
don't see one in your post. When you need to cast to get the job done, it is
often a indication you need to reconsider your design. A good design rarely
needs casts.
If all DataProcessor classes share the same interface you can do away with
the casting and the enums.
For example:
class DataProcessor
{
public:
virtual int process(int x) = 0;
};
class DataProcessor1 : public DataProcessor
{
public:
virtual int process(int x)
{ // Perform OP1
return x*x;
}
};
class DataProcessor2 : public DataProcessor
{
public:
DataProcessor2(int m) : m_(m){}
virtual int process(int x)
{ // Perform OP2
return x*m_;
}
private:
int m_;
};
void Foo(DataProcessor& dp)
{
int i = dp.process(42);
}
int main()
{
DataProcessor1 dp1;
Foo(dp1);
DataProcessor2 dp2(100);
Foo(dp2);
}
The advantage of this approach is that you can derive other classes from
DataProcessor without needing to change the DataProcessor class or the Foo
function. Classes derived from DataProcessor may have the necessary
parameters as class members as illustrated by the DataProcessor2 class.
Note that C++ is case sensitive; 'Class' 'If', 'Else' and 'Public' are not
C++ keywords, 'class', 'if', 'else' and 'public' are.
HTH
--
Peter van Merkerk
peter.van.merkerk(at)dse.nl