By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,159 Members | 956 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,159 IT Pros & Developers. It's quick & easy.

Which derived class is it?

P: n/a
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
Share this Question
Share on Google+
24 Replies


P: n/a

"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

P: n/a
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

P: n/a
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

P: n/a
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

P: n/a
Jeff Schwab <je******@comcast.net> wrote in message news:<zb********************@comcast.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

P: n/a
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,daughter>
{
void operator()() { std::cout << "He, do not kick girls !!!" <<
std::endl; }
};
template <> struct kick<son2,daughter>
{
void operator()() { std::cout << "He, do not kick girls !!!" <<
std::endl; }
};
template <> struct kick<daughter,son>
{
void operator()() { std::cout << "Aua, that hurts." << std::endl; }
};
template <> struct kick<daughter,son2>
{
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<instancetype(fam1_),instancetype(fam2_)>()();
// I really expect typos
void kicking(const mama & fam1_,const mama & fam2_)
{
std::cout << typeid(fam1_).name() << " tries to kick ";
std::cout << typeid(fam2_).name() << ": ";

if ( typeid(daughter) == typeid(fam1_) )
if ( typeid(daughter) == typeid(fam2_) )
kick<daughter,daughter>()();
else if ( typeid(son) == typeid(fam2_) )
kick<daughter,son>()();
else if ( typeid(son2) == typeid(fam2_) )
kick<daughter,son2>()();
else throw "Ups, what happend ?";
else if ( typeid(son) == typeid(fam1_) )
if ( typeid(daughter) == typeid(fam2_) )
kick<son,daughter>()();
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,daughter>()();
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

P: n/a


stelios xanthakis wrote:
Jeff Schwab <je******@comcast.net> wrote in message news:<zb********************@comcast.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

P: n/a
"Jeff Schwab" <je******@comcast.net> wrote in message
news:zb********************@comcast.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

P: n/a
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

P: n/a
Patrick Kowalzick wrote:
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?


<snip> bunch of code with very amusing debug messages </>

Here's the approach I use. It relies on adding methods to the classes
involved. In fact, for this to work, the base class has to know which
sub-classes need to fit into the framework.

Btw, there's a good intro to this problem in _D&E_.

<code>

#include <iostream>

class daughter;
class son;
class son2;

class mama
{
public:
virtual void kick( mama& other ) =0;

virtual void get_kicked( daughter& kicker ) =0;
virtual void get_kicked( son& kicker ) =0;
virtual void get_kicked( son2& kicker ) =0;

protected:
mama( ) { };
virtual ~mama( ) { };
};

class daughter: public mama
{
public:
void kick( mama& victim );
void get_kicked( daughter& kicker );
void get_kicked( son& kicker );
void get_kicked( son2& kicker );
};

class son: public mama
{
public:
void kick( mama& victim );
void get_kicked( daughter& kicker );
void get_kicked( son& kicker );
void get_kicked( son2& kicker );
};

class son2: public mama
{
public:
void kick( mama& victim );
void get_kicked( daughter& kicker );
void get_kicked( son& kicker );
void get_kicked( son2& kicker );
};

void daughter::kick( mama& victim )
{
// Here, it is known that "this" points to a daughter.

victim.get_kicked( *this );
}

void daughter::get_kicked( daughter& kicker )
{
// I could kick myself!

std::cout << "daughter kicks daughter\n";
}

void daughter::get_kicked( son& kicker )
{
std::cout << "son kicks daughter\n";
}

void daughter::get_kicked( son2& kicker )
{
std::cout << "son2 kicks daughter\n";
}

void son::kick( mama& victim )
{
// Here, it is known that "this" points to a son.

victim.get_kicked( *this );
}

void son::get_kicked( daughter& kicker )
{
std::cout << "daughter kicks son\n";
}

void son::get_kicked( son& kicker )
{
std::cout << "son kicks son\n";
}

void son::get_kicked( son2& kicker )
{
// And this is my other brother Darryl...

std::cout << "son2 kicks son\n";
}

void son2::kick( mama& victim )
{
// Here, it is known that "this" points to a son2.

victim.get_kicked( *this );
}

void son2::get_kicked( daughter& kicker )
{
std::cout << "daughter kicks son2\n";
}

void son2::get_kicked( son& kicker )
{
std::cout << "son kicks son2\n";
}

void son2::get_kicked( son2& kicker )
{
std::cout << "son2 kicks son2\n";
}

void kicking( mama& fam1, mama& fam2 )
{
fam1.kick( fam2 );
}

int main( )
{
daughter d;
son s;
son2 s2;

kicking( d, d );
kicking( s, d );
kicking( s2, d );

kicking( d, s );
kicking( s, s );
kicking( s2, s );

kicking( d, s2 );
kicking( s, s2 );
kicking( s2, s2 );
}

</code>

Jul 22 '05 #11

P: n/a


Jeff Schwab wrote:
Patrick Kowalzick wrote:
> 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.
Sorry, I left an overloaded method (get_kicked). Please change

virtual void get_kicked( daughter& kicker ) =0;
virtual void get_kicked( son& kicker ) =0;
virtual void get_kicked( son2& kicker ) =0;

to

virtual void get_kicked_by_daughter( daughter& kicker ) =0;
virtual void get_kicked_by_son( son& kicker ) =0;
virtual void get_kicked_by_son2( son2& kicker ) =0;

and make similar adjusments to the derived classes.
> 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?


<snip> bunch of code with very amusing debug messages </>

Here's the approach I use. It relies on adding methods to the classes
involved. In fact, for this to work, the base class has to know which
sub-classes need to fit into the framework.

Btw, there's a good intro to this problem in _D&E_.

<code>

#include <iostream>

class daughter;
class son;
class son2;

class mama
{
public:
virtual void kick( mama& other ) =0;

virtual void get_kicked( daughter& kicker ) =0;
virtual void get_kicked( son& kicker ) =0;
virtual void get_kicked( son2& kicker ) =0;

protected:
mama( ) { };
virtual ~mama( ) { };
};

class daughter: public mama
{
public:
void kick( mama& victim );
void get_kicked( daughter& kicker );
void get_kicked( son& kicker );
void get_kicked( son2& kicker );
};

class son: public mama
{
public:
void kick( mama& victim );
void get_kicked( daughter& kicker );
void get_kicked( son& kicker );
void get_kicked( son2& kicker );
};

class son2: public mama
{
public:
void kick( mama& victim );
void get_kicked( daughter& kicker );
void get_kicked( son& kicker );
void get_kicked( son2& kicker );
};

void daughter::kick( mama& victim )
{
// Here, it is known that "this" points to a daughter.

victim.get_kicked( *this );
}

void daughter::get_kicked( daughter& kicker )
{
// I could kick myself!

std::cout << "daughter kicks daughter\n";
}

void daughter::get_kicked( son& kicker )
{
std::cout << "son kicks daughter\n";
}

void daughter::get_kicked( son2& kicker )
{
std::cout << "son2 kicks daughter\n";
}

void son::kick( mama& victim )
{
// Here, it is known that "this" points to a son.

victim.get_kicked( *this );
}

void son::get_kicked( daughter& kicker )
{
std::cout << "daughter kicks son\n";
}

void son::get_kicked( son& kicker )
{
std::cout << "son kicks son\n";
}

void son::get_kicked( son2& kicker )
{
// And this is my other brother Darryl...

std::cout << "son2 kicks son\n";
}

void son2::kick( mama& victim )
{
// Here, it is known that "this" points to a son2.

victim.get_kicked( *this );
}

void son2::get_kicked( daughter& kicker )
{
std::cout << "daughter kicks son2\n";
}

void son2::get_kicked( son& kicker )
{
std::cout << "son kicks son2\n";
}

void son2::get_kicked( son2& kicker )
{
std::cout << "son2 kicks son2\n";
}

void kicking( mama& fam1, mama& fam2 )
{
fam1.kick( fam2 );
}

int main( )
{
daughter d;
son s;
son2 s2;

kicking( d, d );
kicking( s, d );
kicking( s2, d );

kicking( d, s );
kicking( s, s );
kicking( s2, s );

kicking( d, s2 );
kicking( s, s2 );
kicking( s2, s2 );
}

</code>


Jul 22 '05 #12

P: n/a
Hi Jeff,
<snip> bunch of code with very amusing debug messages </>
debug messages ?
Here's the approach I use. It relies on adding methods to the classes
involved. In fact, for this to work, the base class has to know which
sub-classes need to fit into the framework.
What I do not like at this solution is the fact, that each child MUST be
able to kick another child. But how can we implement a class "baby" which
neither kicks anybody nor could be kicked.

The abstract definition forces to include this, what is semantically wrong
(and political incorrect). Private or proteced declarations do not help
here, while the interface is derived and accesed via the base class (please
correct me if I am too wrong).
Btw, there's a good intro to this problem in _D&E_.
Ups, sorry. What is D&E ?
class daughter: public mama
{
public:
void kick( mama& victim );
void get_kicked( daughter& kicker );
void get_kicked( son& kicker );
void get_kicked( son2& kicker );
};
BTW, very exemplary variable naming :-).
// I could kick myself!


OK, but I do not want to ;-).

Patrick
Jul 22 '05 #13

P: n/a
Hi Jeff,
Sorry, I left an overloaded method (get_kicked). Please change.


No Problem :-)

I just meant the overload of the "final" function "kicking". Hidden there
inside may reside as many overloads like you want :-). So this is fine.

Patrick

Jul 22 '05 #14

P: n/a
"Patrick Kowalzick" <Pa***************@cern.ch> wrote...
[...]
Btw, there's a good intro to this problem in _D&E_.


Ups, sorry. What is D&E ?


"The {D}esign {and} {E}volution of C++" by Bjarne Stroustrup
(ISBN 0-201-54330-3). In case you haven't found it out yet...

V
Jul 22 '05 #15

P: n/a

Patrick Kowalzick wrote:
<snip> bunch of code with very amusing debug messages </>


debug messages ?


Your std::cout << "facetious quote" lines.
Here's the approach I use. It relies on adding methods to the
classes involved. In fact, for this to work, the base class has to
know which sub-classes need to fit into the framework.


What I do not like at this solution is the fact, that each child MUST
be able to kick another child. But how can we implement a class "baby"
which neither kicks anybody nor could be kicked.

The abstract definition forces to include this, what is semantically
wrong (and political incorrect). Private or proteced declarations do
not help here, while the interface is derived and accesed via the base
class (please correct me if I am too wrong).


Multiple inheritance to the rescue!

(Forgive me, but I'm changing case to have the convention that
user-defined types begin with capital letters, so I can have a Kicker
class that doesn't interfere with variables called "kicker.")

Move the pure virtual kick/get_kicked declarations into a separate,
abstract class, called "Kicker." Derive Daughter, Son, and Son2 from
Mama *and* from Kicker. Then, Baby can be derived from Mama without
knowing anything about kicking.
Btw, there's a good intro to this problem in _D&E_.


Ups, sorry. What is D&E ?


http://www.research.att.com/~bs/dne.html
class daughter: public mama
{
public:
void kick( mama& victim );
void get_kicked( daughter& kicker );
void get_kicked( son& kicker );
void get_kicked( son2& kicker );
};

BTW, very exemplary variable naming :-).

// I could kick myself!

OK, but I do not want to ;-).

Patrick


Jul 22 '05 #16

P: n/a


Jeremy Cowles wrote:
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?


namespace Logic
{
struct A { };
struct B { };
struct C { };
}

namespace Gui
{
void draw( A const& ) { }
void draw( B const& ) { }
void draw( C const& ) { }
}

Jul 22 '05 #17

P: n/a


Jeff Schwab wrote:


Jeremy Cowles wrote:
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?

namespace Logic
{
struct A { };
struct B { };
struct C { };
}

namespace Gui
{
void draw( A const& ) { }
void draw( B const& ) { }
void draw( C const& ) { }
}


D'oh!

Should be:

namespace Gui
{
void draw( Logic::A const& ) { }
void draw( Logic::B const& ) { }
void draw( Logic::C const& ) { }
}

Jul 22 '05 #18

P: n/a
Hi Jeff,
>><snip> bunch of code with very amusing debug messages </> >
> debug messages ?


Your std::cout << "facetious quote" lines.


You have brothers and sisters? I have.....a lot :-).
Multiple inheritance to the rescue!
Ups, sorry, I left a hole open. I think I have to come out with some more
informations.

I have quite a lot of specialized template functors, depending on three
arguments - at all quite a lot functions. I use the templated functors to
get "compile-time" inheritance which works fine (really similar like my
first example).

[start OT]
[if reader = basic_hater goto end OT]

Now to the problem:
All the functions I have in C++ and they shall stay there. But sadly enough
I no have to go to Visual Basic. Inheritance and RTTI (not the ANSI one but
the managed C++ version :-( ) seems to me the only possibility to go there
without to much thinking.
One problem here is that my "compile-time" advantages are just dying, but I
do not mind. It should not be that overhead.

That all works fine on the VB-Side (I am so sorry):

Dim Son = New familyfromcpp.son
Dim Daughter = New familyfromcpp.daughter

Dim action As Object
action = New familyfromcpp.kickingclass
action.kicking(Son,Daughter)
action.kicking(Daughter,Son)

Quite an easy syntax calling the powerful C++ library *gg*. In fact daughter
and son must mot be classes, they could be constants or something else as
well. But I like the version with classes for some reasons.

[end OT - Please forgive me. Do not ban me. Please. ]

[copy paste] Multiple inheritance to the rescue!
I am sorry (for me). No multiple inheritance. No Policies. Back to the
roots.

The keyword I found yet (Thx Chris) is "double dispatching" (in fact
multiple dispatching) and the belonging chapters in the books "Modern C++
Design" and "Effective C++". But I find both rather complicated approaches
and I am searching an easier one. Anyway I like most the Brute-force
approach from Andrei.

So coming back to: 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).


Exactly this could be very useful here. But I want to avoid the huge if else
blocks. And I wanted to avoid macro-programming but it could be more
understandable:

#define call_kick(type1,type2) \
if ( typeid(type1) == typeid(fam1_) && typeid(type2) == typeid(fam2_)) \
kick<type1,type2>()(); else

// function which shall be executed
void kicking(const mama & fam1_,const mama & fam2_)
{
std::cout << typeid(fam1_).name() << " tries to kick ";
std::cout << typeid(fam2_).name() << ": ";

call_kick(daughter,daughter)
call_kick(daughter,son)
call_kick(daughter,son2)
call_kick(son,daughter)
call_kick(son,son)
call_kick(son,son2)
call_kick(son2,daughter)
call_kick(son2,son)
call_kick(son2,son2)
throw "Ups, what happend ?";
}

Macros for the rescue !!!

Regards,
Patrick
Jul 22 '05 #19

P: n/a
Nils Petter Vaskinn <no@spam.for.me.invalid> wrote in message news:<pa****************************@spam.for.me.i nvalid>...
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.


Thing is, typeID *can* be achieved with virtuals+static local variables.

So either give us "virtual variables" (variables that are in the virtual
table: meta programming), or don't. typeID is in the middle.

the truth is that typeID was required because exceptions have to throw
objects (for some reason). So typeID would definitelly be part of the
language. Book writers should warn about this situation: typeID it's not
a serious feature; it was there and they decided to give it to the programmers
for debugging purposes. Apart from that, typeID should be avoided like goto.

stelios
Jul 22 '05 #20

P: n/a
> > namespace Logic
{
struct A { };
struct B { };
struct C { };
}

namespace Gui
{
void draw( A const& ) { }
void draw( B const& ) { }
void draw( C const& ) { }
}

Thats cool, but it is not what was described. Here is the solution that was
suggested:

namespace Logic
{
struct A { void draw( ) { } };
struct B : A { void draw( ) { } };
struct C : A { void draw( ) { } };
}
And this forces the logic to know how to draw, and my question is: isn't
this bad?
Jeremy

Jul 22 '05 #21

P: n/a
"David Harmon" <so****@netcom.com> wrote in message
news:3f***************@news.west.earthlink.net...
FAQ before posting. You can get the FAQ at:
http://www.parashift.com/cpp-faq-lite/


I think that should read http://www.parashift.com/c++-faq-lite/
Jul 22 '05 #22

P: n/a
Jeremy Cowles wrote:
namespace Logic
{
struct A { };
struct B { };
struct C { };
}

namespace Gui
{
void draw( Logic::A const& ) { }
void draw( Logic::B const& ) { }
void draw( Logic::C const& ) { }
}

Thats cool, but it is not what was described. Here is the solution that was
suggested:

namespace Logic
{
struct A { void draw( ) { } };


Method "draw" should be virtual if {B,C}::draw are to override it.
struct B : A { void draw( ) { } };
struct C : A { void draw( ) { } };
}
And this forces the logic to know how to draw, and my question is: isn't
this bad?


It's "bad" in the sense that it's semantically ugly, and slightly less
efficient than the alternative I suggested.

-Jeff

Jul 22 '05 #23

P: n/a
"Jeffrey Schwab" <je******@comcast.net> wrote in message
news:br**********@news1brm.Central.Sun.COM...
Jeremy Cowles wrote:
namespace Logic
{
struct A { };
struct B { };
struct C { };
}

namespace Gui
{
void draw( Logic::A const& ) { }
void draw( Logic::B const& ) { }
void draw( Logic::C const& ) { }
}


Thats cool, but it is not what was described. Here is the solution that was suggested:

namespace Logic
{
struct A { void draw( ) { } };


Method "draw" should be virtual if {B,C}::draw are to override it.
struct B : A { void draw( ) { } };
struct C : A { void draw( ) { } };
}
And this forces the logic to know how to draw, and my question is: isn't
this bad?


It's "bad" in the sense that it's semantically ugly, and slightly less
efficient than the alternative I suggested.


Much more than symantically ugly, it is conceptually wrong. In order to
provide a different UI, you must redesign the classes or add a new draw
method - ie, it couples the business logic and the front-end. So I guess I
was just wondering if the designer knew something I don't.

Jeremy

Jul 22 '05 #24

P: n/a
Jeremy Cowles wrote:
"Jeffrey Schwab" <je******@comcast.net> wrote in message
news:br**********@news1brm.Central.Sun.COM...
Jeremy Cowles wrote:
>namespace Logic
>{
> struct A { };
> struct B { };
> struct C { };
>}
>
>namespace Gui
>{
> void draw( Logic::A const& ) { }
> void draw( Logic::B const& ) { }
> void draw( Logic::C const& ) { }
>}

Thats cool, but it is not what was described. Here is the solution that
was
suggested:

namespace Logic
{
struct A { void draw( ) { } };
Method "draw" should be virtual if {B,C}::draw are to override it.

struct B : A { void draw( ) { } };
struct C : A { void draw( ) { } };
}
And this forces the logic to know how to draw, and my question is: isn't
this bad?


It's "bad" in the sense that it's semantically ugly, and slightly less
efficient than the alternative I suggested.

Much more than symantically ugly, it is conceptually wrong. In order to
provide a different UI, you must redesign the classes or add a new draw
method - ie, it couples the business logic and the front-end.


That doesn't make it "wrong," it's just monolithic. Lots of large
pieces of code have uglier couplings than this, but work well anyway for
a wide range of people. (Just ask any linux kernel or perl internals
developer.)
So I guess I
was just wondering if the designer knew something I don't.
I don't think so.

Jeremy


Jul 22 '05 #25

This discussion thread is closed

Replies have been disabled for this discussion.