casting to a derived class

N

Naomi

I need to make software engineering decision to do with using a
derived data type in a container class. So for example, if I have an
Edge class, and I want to make a Edge object which contains two
NumberVertices instead of Vertices, I can either just use a non-
templated Edge class which stores pointers to my NumberVertices and
leave it up to the programmer to cast back again to NumberVertex (this
type of casting only works with pointers), or I can use a template
class.

I've been looking around on info on this, and I can't decide which is
a better approach. I find using template classes gives you very
difficult to interpret error messages, but I wonder if using this
pointer/static cast approach will give me some typing problems later
on.



/***************************************************
* Using pointers and static casts to to access objects of derived
class:
****************************************************/
#include <iostream>


class Vertex
{
public:
Vertex(void){};
};


class NumberVertex :
public Vertex
{
public:
NumberVertex(void){};
NumberVertex(int num):number(num){};
int getNum(){return number;}
public:
~NumberVertex(void){};
protected:
int number;
};

class Edge
{
public:
Edge(Vertex* a, Vertex* b):v1(a),v2(b){};
Vertex* getV1(){return v1;}
Vertex* getV2(){return v2;}
protected:
Vertex* v1;
Vertex* v2;
};

int main(int argc, char **argv){
NumberVertex* v1 = new NumberVertex(1);
NumberVertex* v2 = new NumberVertex(2);
Edge e(v1, v2);

NumberVertex* ev1 = (NumberVertex*) e.getV1();
NumberVertex* ev2 = (NumberVertex*) e.getV2();

std::cout << "V1: " << ev1->getNum() << std::endl;
std::cout << "V2: " << ev2->getNum() << std::endl;

}


/***************************************************
* Using template class:
****************************************************/
#include <iostream>

class Vertex
{
public:
Vertex(void){};
};

class NumberVertex :
public Vertex
{
public:
NumberVertex(void){};
NumberVertex(int num):number(num){};
int getNum(){return number;}
public:
~NumberVertex(void){};
protected:
int number;
};

template <class Vert> class Edge
{
public:
Edge(Vert& a, Vert& b):v1(a),v2(b){};
Vert& getV1(){return v1;}
Vert& getV2(){return v2;}
protected:
Vert v1;
Vert v2;
};
 
V

Victor Bazarov

Naomi said:
I need to make software engineering decision to do with using a
derived data type in a container class. So for example, if I have an
Edge class, and I want to make a Edge object which contains two
NumberVertices instead of Vertices, I can either just use a non-
templated Edge class which stores pointers to my NumberVertices and
leave it up to the programmer to cast back again to NumberVertex (this
type of casting only works with pointers), or I can use a template
class.

I've been looking around on info on this, and I can't decide which is
a better approach. I find using template classes gives you very
difficult to interpret error messages, but I wonder if using this
pointer/static cast approach will give me some typing problems later
on.

What you're comparing is "run-time polymorphism" versus "compile-
time polymorphism". I bet if you search for those, you will find
more information which one is more appropriate in what case.

V
 
B

BobR

Naomi said:
#include <iostream>
class Vertex{ public:
Vertex(){}; // (void) not needed in C++
virtual ~Vertex(){}; // suggestion
};

class NumberVertex : public Vertex { public:
NumberVertex(){}; // (void) not needed in C++
NumberVertex( int num ) : number( num ){};
int getNum(){ return number;}
public:
~NumberVertex(){}; // (void) not needed in C++
protected:
int number;
};

class Edge{ public:
Edge( Vertex *a, Vertex *b ) : v1( a ), v2( b ){};
Vertex* getV1(){ return v1;}
Vertex* getV2(){ return v2;}
protected:
Vertex *v1;
Vertex *v2;
};

int main(int argc, char **argv){
NumberVertex *v1 = new NumberVertex( 1 );
NumberVertex *v2 = new NumberVertex( 2 );
Edge e( v1, v2 );
// > NumberVertex* ev1 = (NumberVertex*) e.getV1();
// > NumberVertex* ev2 = (NumberVertex*) e.getV2();

// Why hide a possible error with a 'C' style cast?

NumberVertex *ev1 = dynamic_cast<NumberVertex*>( e.getV1() );
if( not ev1 ){ std::cout << "ERROR\n"; return EXIT_FAILURE; }
// ...etc.
 
T

terminator

I need to make software engineering decision to do with using a
derived data type in a container class. So for example, if I have an
Edge class, and I want to make a Edge object which contains two
NumberVertices instead of Vertices, I can either just use a non-
templated Edge class which stores pointers to my NumberVertices and
leave it up to the programmer to cast back again to NumberVertex (this
type of casting only works with pointers), or I can use a template
class.

I've been looking around on info on this, and I can't decide which is
a better approach. I find using template classes gives you very
difficult to interpret error messages, but I wonder if using this
pointer/static cast approach will give me some typing problems later
on.

/***************************************************
* Using pointers and static casts to to access objects of derived
class:
****************************************************/
#include <iostream>

class Vertex
{
public:
Vertex(void){};

};

class NumberVertex :
public Vertex
{
public:
NumberVertex(void){};
NumberVertex(int num):number(num){};
int getNum(){return number;}
public:
~NumberVertex(void){};
protected:
int number;

};

class Edge
{
public:
Edge(Vertex* a, Vertex* b):v1(a),v2(b){};
Vertex* getV1(){return v1;}
Vertex* getV2(){return v2;}
protected:
Vertex* v1;
Vertex* v2;

};

int main(int argc, char **argv){
NumberVertex* v1 = new NumberVertex(1);
NumberVertex* v2 = new NumberVertex(2);
Edge e(v1, v2);

NumberVertex* ev1 = (NumberVertex*) e.getV1();
NumberVertex* ev2 = (NumberVertex*) e.getV2();

std::cout << "V1: " << ev1->getNum() << std::endl;
std::cout << "V2: " << ev2->getNum() << std::endl;

}

/***************************************************
* Using template class:
****************************************************/
#include <iostream>

class Vertex
{
public:
Vertex(void){};

};

class NumberVertex :
public Vertex
{
public:
NumberVertex(void){};
NumberVertex(int num):number(num){};
int getNum(){return number;}
public:
~NumberVertex(void){};
protected:
int number;

};

template <class Vert> class Edge
{
public:
Edge(Vert& a, Vert& b):v1(a),v2(b){};
Vert& getV1(){return v1;}
Vert& getV2(){return v2;}
protected:
Vert v1;
Vert v2;



};- Hide quoted text -

- Show quoted text -

it depends on how you are going to use it. if v1 and v2 may contain
different types of vertice then the former approach is somehow better,
otherwise the later is better.But if the number of vertex types
derived form 'Vertex' is many and lots of member functions are
prepared for 'Edge' and v1 and v2 are supposed to contain vertice of
the same type.then you may derive a template from a pointer-using
'Edge'.
 
Z

Zachary Turner

it depends on how you are going to use it. if v1 and v2 may contain
different types of vertice then the former approach is somehow better,
otherwise the later is better.

IMNSHO, nothing could possibly be worse than performing a cast to a
derived class. In 99% of situations, there is a way to code around it.
 
T

terminator

IMNSHO, nothing could possibly be worse than performing a cast to a
derived class. In 99% of situations, there is a way to code around it.

I agree but I am used to follow a rule that says :"do the hard/dirty
things just once".I mean something like this:


class edge{//hard thing
// put big member functions here.
};

template <class vert>
struct tedge:edge{//dirty thing
/*just define the inline interface that perform casts and call
edge::functions*/
};

regards,
FM.
 
T

Thomas J. Gritzan

terminator wrote:
Zachary Turner said:
I agree but I am used to follow a rule that says :"do the hard/dirty
things just once".I mean something like this:


class edge{//hard thing
// put big member functions here.
};

template <class vert>
struct tedge:edge{//dirty thing
/*just define the inline interface that perform casts and call
edge::functions*/
};

Why do you need to cast to call base class' functions?
 
T

terminator

terminator wrote:










Why do you need to cast to call base class' functions?

IMHO it is really dirty to put a casting on every line that uses
'edge',so I decided to put the dirty part in the definition of the
'tedge' template.I dont know how the compiler handles templates behind
the scene ,so I decide to put the working part of the code in 'edge'
in order to decrease the code size(I think that templates increase the
code size ) because we are going to use the template for objects of
the same herarchy graph and we are just considering the behavior of
the Grand base type.

regards,
FM
 
G

Gavin Deane

Zachary's comment (and the preceding discussion) is about casting
*from* a base class *to* a derived class.
IMHO it is really dirty to put a casting on every line that uses
'edge',so I decided to put the dirty part in the definition of the
'tedge' template.I dont know how the compiler handles templates behind
the scene ,so I decide to put the working part of the code in 'edge'
in order to decrease the code size(I think that templates increase the
code size ) because we are going to use the template for objects of
the same herarchy graph and we are just considering the behavior of
the Grand base type.

You don't seem to have answered the question. The original discussion
was about casting from base to derived. You are now talking about
calling base class functions from a derived class.

1. That's the other way around - you do understand that's a completely
different question don't you?
2. Why do you need to cast to go that way?

class edge
{
public:
void foo()
{ /* hard thing - big member function */ }
};

template <class vert>
struct tedge : edge
{
// Dirty thing - apparently, but what's dirty about it, and where
is the need for a cast?
void foo() { edge::foo(); }
};

Gavin Deane
 
T

terminator

Zachary's comment (and the preceding discussion) is about casting
*from* a base class *to* a derived class.







You don't seem to have answered the question. The original discussion
was about casting from base to derived. You are now talking about
calling base class functions from a derived class.

1. That's the other way around - you do understand that's a completely
different question don't you?
2. Why do you need to cast to go that way?

class edge
{
public:
void foo()
{ /* hard thing - big member function */ }

};

template <class vert>
struct tedge : edge
{
// Dirty thing - apparently, but what's dirty about it, and where
is the need for a cast?
void foo() { edge::foo(); }

};

Gavin Deane- Hide quoted text -

- Show quoted text -

'tedge' needs to call some functions from base ('foo' as you wrote)
particularly the ctor/dtor inline.the parameter type('vert') to
'tedge' must be derived from 'vertex'(the grand base for parameter
types) and this template is supposed to handle downward castings so
that there is not a need for down cast from a 'vertex' in every line
that contains a call to 'edge' functions.So the 'tedge' is supposed to
do the dirty portion of the code(down casts) and 'edge' does the hard
thing('foo').

regards,
FM
 

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

Forum statistics

Threads
473,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top