473,809 Members | 2,798 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Which derived class is it?

I would like to have a function that takes as an argument a base class but
performs differently depending on which type of derived class is passed.
Can I tell which derived class is passed?

For example:

class Base
{ //...
};

class D1: public Base
{ //...
};

class D2: public Base
{ //...
};

void f(Base b)
{
// Do one thing if b is of type D1, Do another if b is of type D2
}

Is this the right idea? Or do I have to write multiple copies of f()
with arguments overloaded with the derived classes?

Brad
Jul 22 '05 #1
24 1761

"Brad Marts" <ma***@phy.duke .edu> wrote in message
news:pa******** *************** *****@phy.duke. edu...
I would like to have a function that takes as an argument a base class but
performs differently depending on which type of derived class is passed.
Can I tell which derived class is passed?

For example:

class Base
{ //...
};

class D1: public Base
{ //...
};

class D2: public Base
{ //...
};

void f(Base b)
{
// Do one thing if b is of type D1, Do another if b is of type D2
}

Is this the right idea? Or do I have to write multiple copies of f()
with arguments overloaded with the derived classes?


I would certainly not write multiple copies. You might want to read up more
on examples of polymorphism. The power of this is that you don't have to
write multiple copies of functions. On the other hand, you normally don't
want to have to check what the subtype is, either. Normally what you want
to do is achieve "performing differently" by calling functions on those
objects that get passed in. In other words, you bury the different
performance within the subclasses themselves. For example, in your f()
function, what do you want to do? Let's say it's to display something about
the object. So you write a function called "display" and put it in Base and
make it virtual. Then in D1 and D2 you define those functions again,
separately, but you make them do 2 different things. For example,

void D1::display()
{
cout << "This is an object of type D1!";
}

void D2::display()
{
cout << "This is an object of type D2!";
}

In your f function, you merely write
b.display(), and then the correct thing will be displayed, depending on the
type, without you having to know or care in the code. There's a catch here
though - you can't do it if you pass the Base parameter by value like that.
You have to pass it by reference (Base& b), or pionter (Base* pB).
Jul 22 '05 #2
On Mon, 15 Dec 2003 10:34:48 -0700 in comp.lang.c++, "Brad Marts"
<ma***@phy.duke .edu> was alleged to have written:
I would like to have a function that takes as an argument a base class but
performs differently depending on which type of derived class is passed.


This issue is covered in Marshall Cline's C++ FAQ. See the topic
"[20] Inheritance — virtual functions". It is always good to check the
FAQ before posting. You can get the FAQ at:
http://www.parashift.com/cpp-faq-lite/
Jul 22 '05 #3
Brad Marts <ma***@phy.duke .edu> wrote in message
news:pa******** *************** *****@phy.duke. edu...
I would like to have a function that takes as an argument a base class but
performs differently depending on which type of derived class is passed.
Can I tell which derived class is passed?

For example:

class Base
{ //...
};

class D1: public Base
{ //...
};

class D2: public Base
{ //...
};

void f(Base b)
{
// Do one thing if b is of type D1, Do another if b is of type D2
}

Is this the right idea? Or do I have to write multiple copies of f()
with arguments overloaded with the derived classes?

Brad


The idea is all right. However the implementation is not quite right.

Your f function could be altered like this:

void f(Base& b)
{
if(typeid(b) == typeid(D1))/*Do one thing here*/

else if(typeid(b) == typeid(D2))/*Do another here*/
}

Basically used RTTI above.
Jul 22 '05 #4
Brad Marts wrote:
I would like to have a function that takes as an argument a base class but
performs differently depending on which type of derived class is passed.


IMNSHO:

The worst of all possible worlds is to test the argument's run-time type
with a switch statement, if-else block, or the like (the "switch on
type" approach).

The next worst of all possible worlds is to code a different version of
the function for each derived type that may be an argument to it (the C
approach).

The usual solution is to give the base class a virtual method, giving
each derived class the option of overriding the method:

struct Base { virtual void behave( ) { /* do one thing */ } };
struct Derived1 { void behave( ) { /* do another */ } };
struct Derived2 { void behave( ) { /* do yet another */ } };

void f( Base& b ) { b.behave( ); }

My favorite solution is the generic approach, which allows you to avoid
the performance and space overhead that accompany the use of virtual
functions:

struct Base { void behave( ) { /* do one thing */ } };
struct Derived1 { void behave( ) { /* do another */ } };
struct Derived2 { void behave( ) { /* do yet another */ } };

template< typename T >
void f( T& t ) { t.behave( ); }

This causes the compiler to implement the indirection at compile time,
instead of run time. The biggest barrier I've had to using this
approach is the pile of existing code (written by yours truly) that
relies on run-time indirection.

Hth,
Jeff

Jul 22 '05 #5
Jeff Schwab <je******@comca st.net> wrote in message news:<zb******* *************@c omcast.com>...
Brad Marts wrote:
I would like to have a function that takes as an argument a base class but
performs differently depending on which type of derived class is passed.
IMNSHO:

The worst of all possible worlds is to test the argument's run-time type
with a switch statement, if-else block, or the like (the "switch on
type" approach).


OT:
And that's why typeID was maybe a not-so-good idea. It can be malused.
The next worst of all possible worlds is to code a different version of
the function for each derived type that may be an argument to it (the C
approach).

C approach would be that each object will have a member my_type,
which will be used in a switch/if. non-OOP. callbacks would be
the other solution, but that's why C++ is here for.
The usual solution is to give the base class a virtual method, giving
each derived class the option of overriding the method:

struct Base { virtual void behave( ) { /* do one thing */ } };
struct Derived1 { void behave( ) { /* do another */ } };
struct Derived2 { void behave( ) { /* do yet another */ } };

void f( Base& b ) { b.behave( ); }

You forgot inheritance?

struct Derrived1 : Base { ... };

Of course.
My favorite solution is the generic approach, which allows you to avoid
the performance and space overhead that accompany the use of virtual
functions:

struct Base { void behave( ) { /* do one thing */ } };
struct Derived1 { void behave( ) { /* do another */ } };
struct Derived2 { void behave( ) { /* do yet another */ } };

template< typename T >
void f( T& t ) { t.behave( ); }


Here on the other hand, we don't need inheritance indeed.
'Derrived1' is not really Derrived but just named so.

Just some more info for the OP:

If -the polymorphic- function "f" has more code:

void f (T &t)
{
...lots of code...
t.behave();
...lots of code...
}

The extra code will be duplicated with each specialization
and thus is not suitable for "embedded systems" where available
memory is 640kb.

Moreover, we are studying a simple case with just one virtual
function. If f() calls two virtuals, "behave1" and "behave2"
then OOP is definitelly superior.
cheers,

stelios
Jul 22 '05 #6
Hi Jeff,
The worst of all possible worlds is to test the argument's run-time type
with a switch statement, if-else block, or the like (the "switch on
type" approach).

The next worst of all possible worlds is to code a different version of
the function for each derived type that may be an argument to it (the C
approach).


Hmm, this leads me to the next question:

given the case you have to call a function depending on two Instances of a
class, what shall we do then?
I append a small example to demonstrate you the Problem I have. Additionally
there is another constraint: no function overloading (a real-world reason
:-( ) for the final function "kicking" which is called out of main.

Please take a closer look at the function kicking. The if..else table is a
real horror. But how to solve it in an easier way?

Regards,
Patrick

// CODE STARTS

#include <iostream>

// small hierachy
// abstact base class, virtual for RTTI
class mama {
protected:
mama() {};
virtual ~mama() {};
};
class daughter : public mama {};
class son : public mama {};
class son2 : public mama {};

// small action functors
template <typename T1,typename T2> struct kick;
template <typename T> struct kick<T,T>
{
void operator()() { std::cout << "Look mum, I am kicking me." <<
std::endl; }
};
template <> struct kick<son,daught er>
{
void operator()() { std::cout << "He, do not kick girls !!!" <<
std::endl; }
};
template <> struct kick<son2,daugh ter>
{
void operator()() { std::cout << "He, do not kick girls !!!" <<
std::endl; }
};
template <> struct kick<daughter,s on>
{
void operator()() { std::cout << "Aua, that hurts." << std::endl; }
};
template <> struct kick<daughter,s on2>
{
void operator()() { std::cout << "Aua, that hurts." << std::endl; }
};
template <> struct kick<son,son2>
{
void operator()() { std::cout << "son2 is crying running to mama" <<
std::endl; }
};
template <> struct kick<son2,son>
{
void operator()() { std::cout << "son is kicking back" << std::endl; }
};

// function which shall be executed
// uuuuuhhhhh, this is really ugly,
// just for a call kick<instancety pe(fam1_),insta ncetype(fam2_)> ()();
// I really expect typos
void kicking(const mama & fam1_,const mama & fam2_)
{
std::cout << typeid(fam1_).n ame() << " tries to kick ";
std::cout << typeid(fam2_).n ame() << ": ";

if ( typeid(daughter ) == typeid(fam1_) )
if ( typeid(daughter ) == typeid(fam2_) )
kick<daughter,d aughter>()();
else if ( typeid(son) == typeid(fam2_) )
kick<daughter,s on>()();
else if ( typeid(son2) == typeid(fam2_) )
kick<daughter,s on2>()();
else throw "Ups, what happend ?";
else if ( typeid(son) == typeid(fam1_) )
if ( typeid(daughter ) == typeid(fam2_) )
kick<son,daught er>()();
else if ( typeid(son) == typeid(fam2_) )
kick<son,son>() ();
else if ( typeid(son2) == typeid(fam2_) )
kick<son,son2>( )();
else throw "Ups, what happend ?";
else if ( typeid(son2) == typeid(fam1_) )
if ( typeid(daughter ) == typeid(fam2_) )
kick<son2,daugh ter>()();
else if ( typeid(son) == typeid(fam2_) )
kick<son2,son>( )();
else if ( typeid(son2) == typeid(fam2_) )
kick<son2,son2> ()();
else throw "Ups, what happend ?";
else throw "Ups, what happend ?";
}
// examples
int main()
{
kicking( son() , daughter() );
kicking( daughter() , son() );
kicking( son() , son() );
kicking( son() , son2() );
kicking( son2() , son() );
kicking( son2() , daughter() );

return 0;
}

// CODE ENDS
Jul 22 '05 #7


stelios xanthakis wrote:
Jeff Schwab <je******@comca st.net> wrote in message news:<zb******* *************@c omcast.com>...
Brad Marts wrote:
I would like to have a function that takes as an argument a base class but
performs differently depending on which type of derived class is passed.


IMNSHO:

The worst of all possible worlds is to test the argument's run-time type
with a switch statement, if-else block, or the like (the "switch on
type" approach).


OT:
And that's why typeID was maybe a not-so-good idea. It can be malused.
The next worst of all possible worlds is to code a different version of
the function for each derived type that may be an argument to it (the C
approach).


C approach would be that each object will have a member my_type,
which will be used in a switch/if. non-OOP. callbacks would be
the other solution, but that's why C++ is here for.


Yes, you're right. Having different C-style functions, as I suggested,
does not provide polymorphism. However, it is possible to get
compile-time polymorphism using overloaded functions:

struct A { void f( ) { /* do one thing */ } };
struct B { void f( ) { /* do another */ } };
struct C { void f( ) { /* do yet another */ } };

void f( A& a ) { a.f( ); }
void f( B& b ) { b.f( ); }
void f( C& c ) { c.f( ); }
The usual solution is to give the base class a virtual method, giving
each derived class the option of overriding the method:

struct Base { virtual void behave( ) { /* do one thing */ } };
struct Derived1 { void behave( ) { /* do another */ } };
struct Derived2 { void behave( ) { /* do yet another */ } };

void f( Base& b ) { b.behave( ); }


You forgot inheritance?

struct Derrived1 : Base { ... };

Of course.


You're right again. Sorry for omission of vital detail.
My favorite solution is the generic approach, which allows you to avoid
the performance and space overhead that accompany the use of virtual
functions:

struct Base { void behave( ) { /* do one thing */ } };
struct Derived1 { void behave( ) { /* do another */ } };
struct Derived2 { void behave( ) { /* do yet another */ } };

template< typename T >
void f( T& t ) { t.behave( ); }

Here on the other hand, we don't need inheritance indeed.
'Derrived1' is not really Derrived but just named so.

Just some more info for the OP:

If -the polymorphic- function "f" has more code:

void f (T &t)
{
...lots of code...
t.behave();
...lots of code...
}

The extra code will be duplicated with each specialization
and thus is not suitable for "embedded systems" where available
memory is 640kb.

Moreover, we are studying a simple case with just one virtual
function. If f() calls two virtuals, "behave1" and "behave2"
then OOP is definitelly superior.


These are all OOP approaches. ITYM "run-time indirection."

-Jeff

Jul 22 '05 #8
"Jeff Schwab" <je******@comca st.net> wrote in message
news:zb******** ************@co mcast.com...
Brad Marts wrote:
I would like to have a function that takes as an argument a base class but performs differently depending on which type of derived class is passed.


IMNSHO:

The worst of all possible worlds is to test the argument's run-time type
with a switch statement, if-else block, or the like (the "switch on
type" approach).

The next worst of all possible worlds is to code a different version of
the function for each derived type that may be an argument to it (the C
approach).

The usual solution is to give the base class a virtual method, giving
each derived class the option of overriding the method:

struct Base { virtual void behave( ) { /* do one thing */ } };
struct Derived1 { void behave( ) { /* do another */ } };
struct Derived2 { void behave( ) { /* do yet another */ } };

void f( Base& b ) { b.behave( ); }

I am very new to C++, but I was wondering: what if the function f( ) does
not belong in the class? For example, say the class is logic for some
business process, which holds some displayable state, and function f( )
displays this state; wouldn't it be wrong to mix the GUI code in with the
logic?

Jeremy
Jul 22 '05 #9
On Tue, 16 Dec 2003 02:53:04 -0800, stelios xanthakis wrote:
OT:
And that's why typeID was maybe a not-so-good idea. It can be malused.


So can sliced bread, but that doesn't mean it was a bad idea. Lots of good
thigs can be malused, the solution is not to do it.

Still I agree that most of the time an overloaded (I prefer virtual)
function will do better.

--
NPV

"the large print giveth, and the small print taketh away"
Tom Waits - Step right up

Jul 22 '05 #10

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

Similar topics

0
1576
by: Anand | last post by:
class base: def __setattr__(self,attr,key,*unexpected): print "Base Class :",attr,key,unexpected,self.__dict__ self.__dict__ = key def __getattr__(self,attr,*unexpected): print "Base Class :",attr,unexpected,self.__dict__ return self.__dict__ class derived(base): def __setattr__(self,attr,key,*unexpected):
10
3337
by: Bhan | last post by:
Using Ptr of derived class to point to base class and viceversa class base { .... } class derived : public base { .... }
10
1411
by: Julia | last post by:
Hi Please can someone explain this behaviour: I have a MustInherit Base class and a Derived class that Inherits Base and Shadows a method in the base class. If I Dim a variable of type Derived and New it as Derived the code in the Derived class is called. However, if I Dim the variable as type Base but New it as type Derived the Base class code is called - I would expect the code in
4
5249
by: Jeff | last post by:
The derived class below passes a reference to an object in its own class to its base calss constructor. The code compiles and will run successfully as long as the base class constructor does not attempt to access the object -- since m_object is not actually created and initizialized until after the base constructor has been called. Any thoughts on the practice below? class Base { public:
6
2501
by: Taran | last post by:
Hi All, I tried something with the C++ I know and some things just seem strange. consider: #include <iostream> using namespace std;
5
1825
by: Bushido Hacks | last post by:
I think this message got lost the first time I sent it, so I'm reposting it. I need a little help with Destructors. Suppose I created a multidimmensional array in a Base class that was also accessable in a Derived class, would I need to delete the array in the Derived class if I declared my destructors as virtual? class Base { public:
15
3089
by: =?Utf-8?B?R2Vvcmdl?= | last post by:
Hello everyone, I met with a strange issue that derived class function can not access base class's protected member. Do you know why? Here is the error message and code. error C2248: 'base::~base' : cannot access protected member declared in
1
1126
by: sasha | last post by:
class Base{ public: std::ostream& operator<<( std::ostream& os, const string &str ) { return print(os); } void print(std:ostream& os){ os<<"Base\n";} };
7
1648
by: eduzea | last post by:
I have some code that compiles with gcc but fails with MS VC 8. I would like to know which one is following the C++ standard. istream& istr = false ? cin : ( * new ifstream("test.txt")) ; Using g++ it compiles. Using MS VC 8 it fails with a message along the lines of: "cannot access private member declared in class 'std::basic_ios<_Elem,_Traits>' "
6
1272
by: Christopher | last post by:
I've seen various ways of doing this, but what I want is to be able to take a base class pointer and know which derived class to cast to. For example I am going to make a base light class, that has a position and intensity. A derived classes class may be a point light which also has a falloff value. The derived class has all the base class methods and data in common, but has the additional falloff value get/set methods.
0
9721
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
1
10378
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 Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
10115
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 protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7653
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6881
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5550
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5687
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4332
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3861
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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.