473,387 Members | 1,621 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,387 software developers and data experts.

RTTI versus a base class enum to represent type

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.

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?

TIA

Jul 19 '05 #1
2 2794
"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
Jul 19 '05 #2
class DataProcessor
{
public:
DataProcessor();
virtual void DoFooProcessing()const=0;
};

class DataProcessorOp1 : public DataProcessor
{
public:
DataProcessorOp1();
virtual void DoFooProcessing()const
{
// Implement op1
}
};

class DataProcessorOp2 : public DataProcessor
{
public:
DataProcessorOp2();
virtual void DoFooProcessing()const
{
// Implement op2
}
};

void Foo(const DataProcessor &dp)
{
dp.DoFooProcessing();
}

In general, it is best in C++ to avoid switching on types.
If you find youself switching on types, you should think "virtual
function".
If you can't put data processing implementation into your
DataProcessor classes
for some reason, consider using the Double Dispatch design pattern. In
that case, you would have something like:

class FooClass
{
virtual Foo(const DataProcessorOp1 &op);
virtual Foo(const DataProcessorOp2 &op);
virtual Foo(const DataProcessorOp3 &op);
// etc
};

class DataProcessor
{
public:
DataProcessor();
virtual void DoFooProcessing(FooClass &foo)const=0;
};

class DataProcessorOp1 : public DataProcessor
{
public:
DataProcessorOp1();
virtual void DoFooProcessing(FooClass &foo)const
{
foo.Foo(*this); // this will call FooClass::Foo(const
DataProcessorOp1 &op);
}
};

class DataProcessorOp2 : public DataProcessor
{
public:
DataProcessorOp2();
virtual void DoFooProcessing(FooClass &foo)const
{
foo.Foo(*this); // this will call FooClass::Foo(const
DataProcessorOp2 &op);
}
};

void Foo(const DataProcessor &dp)
{
FooClass foo;
dp.DoFooProcessing(foo);
}
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.

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?

TIA

Jul 19 '05 #3

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

Similar topics

3
by: tirath | last post by:
Hi all, I have a templated class that derives from a non-templated abstract class. How do I then cast a base class pointer to a <templated> derived class pointer in a generalised fashion? ...
4
by: Daniel Mitchell | last post by:
I'm interested in computational physics and have defined an abstract base class to represent a simulation. Now I want to develop a GUI for setting the member data of classes derived from my base...
2
by: Mark A. Gibbs | last post by:
Given this situation: class Base { public: virtual ~Base(); virtual bool equals(Base const&) const = 0; };
3
by: Steven T. Hatton | last post by:
I'm trying to work out a design for dynamically determining file types, and for generating new files of a given type. I'm curious to know what others think of my current strategy. Is it "so...
5
by: dotNeter | last post by:
I'm studying the RTTI, and my current work is concern for how to get the self-defined type at runtime, that's exactly what the RTTI does. I mean, in my application, I built several self-defined...
33
by: mscava | last post by:
Well I've got a problem, that is more theoretical than practital. I need to know benefits of RTTI. I see another way of doing it... class A { public: ~virtual A() {} enum Type { X, Y, Z }; ...
2
by: Chameleon | last post by:
I know than dynamic_cast check string name of derived to base class and if one of them match, return the pointer of that object or else zero. I suppose, I dynamic_cast instead of strings, checks...
3
by: Chameleon | last post by:
What is better if you want upcasting in intermediate classes like below? Multiple Inheritance and Overloading or simply RTTI? RTTI wants time but MI and Overloading create big objects (because of...
6
by: Generic Usenet Account | last post by:
I ran a small experiment involving RTTI and dynamic casting. Basically what I did was to cast a base class pointer to a derived type (yes, I know that is not kosher). I then performed...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
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
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
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

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.