468,306 Members | 1,201 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,306 developers. It's quick & easy.

construction question

Hello,

Consider the following example. There is a function

foo(Foo1<Foo2foo1) { ... }

The class Foo1 has an empty constructor.

Foo2 can be constructed from an instance foo3 of Foo3.

Can I call:

foo(foo3);

?

Thanks,

JG

Nov 20 '06 #1
11 1144

John Goche wrote:
Hello,

Consider the following example. There is a function

foo(Foo1<Foo2foo1) { ... }

The class Foo1 has an empty constructor.

Foo2 can be constructed from an instance foo3 of Foo3.

Can I call:

foo(foo3);

?
The parameter of the function foo is of type Foo1<Foo2>. The object you
pass when you call foo must therefore be of type Foo1<Foo2or of some
type that can be converted to Foo1<Foo2>. So the only question that
matters is, can an object of type Foo3 be converted to type Foo1<Foo2>.
Unless the answer is yes, your code will not compile.

The fact that a Foo2 can be constructed from a Foo3 is irrelevant. The
function foo does not take a Foo2, it takes a Foo1<Foo2>, which is a
completely different type.

In types that might be more familiar: if Foo1 is std::vector, Foo2 is
std::string and Foo3 is const char*, you have

void foo(std::vector<std::stringv) { ... }

and you are trying to do

foo("some string literal");

A std::vector<std::stringcan not be constructed from a string literal
so the code will not compile. A std::string can be constructed from a
string literal, but that is irrelevant because we are not trying to
construct a std::string, we are trying to construct a
std::vector<std::string>.

Gavin Deane

Nov 20 '06 #2

John Goche wrote:
Hello,

Consider the following example. There is a function

foo(Foo1<Foo2foo1) { ... }
void foo(Foo1< Foo2 >& r_foo1) { }
>
The class Foo1 has an empty constructor.
You mean a default ctor.
That doesn't matter, Foo1 takes a template parameter and nobody knows
if any default(s) is/are providied in its template list.
>
Foo2 can be constructed from an instance foo3 of Foo3.

Can I call:

foo(foo3);
only if the following is valid:

Foo1<Foo2foo1foo2;
Foo3 instance( foo1foo2 );

Which according to the above statement about Foo3, is rather unlikely.

Try:

Foo1< Foo3 foo1foo3;
foo( foo1foo3 );

Nov 20 '06 #3
I had a similar problem.

There I had my List<template>, and in case of template class were 'Car'
and could not pass a List<Ferrarito my function, just like you're
trying to. I had to make a new function, called "Recast".

In this case, I used an rtti function to dynamically cast it, (checking
if it's safe to cast from Ferrari to Cars, throwing an exception if
they can't be casted). You can cut it off, but bad things can happen if
you cast from, like saying, Cars to Ferraris.

/*!
* This is used to recast the whole list because elements can inherit
each other. Win32 only.
*/
template<class NewElementType>
List<NewElementType>&
Recast() {
// we should be aware if both ElementType and NewElementType are
compatible
ElementType tempT;
NewElementType& tempNT = dynamic_cast<NewElementType&>( tempT); //
force runtime to throw exception if we're casting to wrong datatype

List<NewElementType>* recast = (List<NewElementType>*) this;
return *recast;
}
John Goche wrote:
Hello,

Consider the following example. There is a function

foo(Foo1<Foo2foo1) { ... }

The class Foo1 has an empty constructor.

Foo2 can be constructed from an instance foo3 of Foo3.

Can I call:

foo(foo3);

?

Thanks,

JG
Nov 20 '06 #4

gu************@gmail.com wrote:
I had a similar problem.

There I had my List<template>, and in case of template class were 'Car'
and could not pass a List<Ferrarito my function, just like you're
trying to. I had to make a new function, called "Recast".

In this case, I used an rtti function to dynamically cast it, (checking
if it's safe to cast from Ferrari to Cars, throwing an exception if
they can't be casted). You can cut it off, but bad things can happen if
you cast from, like saying, Cars to Ferraris.

/*!
* This is used to recast the whole list because elements can inherit
each other. Win32 only.
*/
template<class NewElementType>
List<NewElementType>&
Recast() {
// we should be aware if both ElementType and NewElementType are
compatible
ElementType tempT;
NewElementType& tempNT = dynamic_cast<NewElementType&>( tempT); //
force runtime to throw exception if we're casting to wrong datatype

List<NewElementType>* recast = (List<NewElementType>*) this;
return *recast;
}

The above invokes undefined behaviour. I can't express to you in words
how dangerous the above code is.
You might think it works in Win32 but in fact it doesn't. Of course, MS
won't tell you that.
Basicly: a recast is dangerous even in the best of conditions - better
a "conversion ctor" which creates a new fully-formed derived object.
And in the event that you are converting a Ferrarri to a car thats done
automatically if the former is derived from the latter( plain copy ctor
invoked). The resulting Cars are spliced Ferraris, of course. Lets
ignore the use of ptrs and polymorphism for now.

The solution is so simple and doesn't need a cast of any kind: a
conversion ctor.

#include <iostream>
#include <list>
#include <algorithm>

struct Car
{
Car() { }
Car(const Car& copy) { }
virtual ~Car() { }
};

struct Ferrarri : public Car
{
Ferrarri() { }
// conversion ctor: (thats all you need)
Ferrarri(const Car& cvt) : Car(cvt) { }
Ferrarri(const Ferrarri& copy) { }
};

int main()
{
std::list< Car cars(10);
std::list< Ferrarri racingcars(10);
// the following splices Ferraris into Cars
std::copy(racingcars.begin(), racingcars.end(), cars.begin());
// the following constructs (not cast) brand new Ferrarris
std::copy(cars.begin(), cars.end(), racingcars.begin());
}

Nov 20 '06 #5
Mr. Salt,

The solution is quite simple to Cars/Ferrarri scenario, but the problem
initially pointed still remains.
How to solve it? The following code is invalid:

void something( std::list<Car>& list_of_cars) {
}
std::list<Ferrarriracingcars(10);
something( racingcars);

That's the error. The dynamic cast will force the runtime to check
inheritance between Ferrari and Cars.

Regards,
Gustavo

Salt_Peter wrote:
gu************@gmail.com wrote:
I had a similar problem.

There I had my List<template>, and in case of template class were 'Car'
and could not pass a List<Ferrarito my function, just like you're
trying to. I had to make a new function, called "Recast".

In this case, I used an rtti function to dynamically cast it, (checking
if it's safe to cast from Ferrari to Cars, throwing an exception if
they can't be casted). You can cut it off, but bad things can happen if
you cast from, like saying, Cars to Ferraris.

/*!
* This is used to recast the whole list because elements can inherit
each other. Win32 only.
*/
template<class NewElementType>
List<NewElementType>&
Recast() {
// we should be aware if both ElementType and NewElementType are
compatible
ElementType tempT;
NewElementType& tempNT = dynamic_cast<NewElementType&>( tempT); //
force runtime to throw exception if we're casting to wrong datatype

List<NewElementType>* recast = (List<NewElementType>*) this;
return *recast;
}

The above invokes undefined behaviour. I can't express to you in words
how dangerous the above code is.
You might think it works in Win32 but in fact it doesn't. Of course, MS
won't tell you that.
Basicly: a recast is dangerous even in the best of conditions - better
a "conversion ctor" which creates a new fully-formed derived object.
And in the event that you are converting a Ferrarri to a car thats done
automatically if the former is derived from the latter( plain copy ctor
invoked). The resulting Cars are spliced Ferraris, of course. Lets
ignore the use of ptrs and polymorphism for now.

The solution is so simple and doesn't need a cast of any kind: a
conversion ctor.

#include <iostream>
#include <list>
#include <algorithm>

struct Car
{
Car() { }
Car(const Car& copy) { }
virtual ~Car() { }
};

struct Ferrarri : public Car
{
Ferrarri() { }
// conversion ctor: (thats all you need)
Ferrarri(const Car& cvt) : Car(cvt) { }
Ferrarri(const Ferrarri& copy) { }
};

int main()
{
std::list< Car cars(10);
std::list< Ferrarri racingcars(10);
// the following splices Ferraris into Cars
std::copy(racingcars.begin(), racingcars.end(), cars.begin());
// the following constructs (not cast) brand new Ferrarris
std::copy(cars.begin(), cars.end(), racingcars.begin());
}
Nov 20 '06 #6
[ Please don't top post ] - rearranged below...
Salt_Peter wrote:
gu************@gmail.com wrote:
I had a similar problem.
>
There I had my List<template>, and in case of template class were 'Car'
and could not pass a List<Ferrarito my function, just like you're
trying to. I had to make a new function, called "Recast".
>
In this case, I used an rtti function to dynamically cast it, (checking
if it's safe to cast from Ferrari to Cars, throwing an exception if
they can't be casted). You can cut it off, but bad things can happen if
you cast from, like saying, Cars to Ferraris.
>
/*!
* This is used to recast the whole list because elements can inherit
each other. Win32 only.
*/
template<class NewElementType>
List<NewElementType>&
Recast() {
// we should be aware if both ElementType and NewElementType are
compatible
ElementType tempT;
NewElementType& tempNT = dynamic_cast<NewElementType&>( tempT); //
force runtime to throw exception if we're casting to wrong datatype
>
List<NewElementType>* recast = (List<NewElementType>*) this;
return *recast;
}
>
>
The above invokes undefined behaviour. I can't express to you in words
how dangerous the above code is.
You might think it works in Win32 but in fact it doesn't. Of course, MS
won't tell you that.
Basicly: a recast is dangerous even in the best of conditions - better
a "conversion ctor" which creates a new fully-formed derived object.
And in the event that you are converting a Ferrarri to a car thats done
automatically if the former is derived from the latter( plain copy ctor
invoked). The resulting Cars are spliced Ferraris, of course. Lets
ignore the use of ptrs and polymorphism for now.

The solution is so simple and doesn't need a cast of any kind: a
conversion ctor.

#include <iostream>
#include <list>
#include <algorithm>

struct Car
{
Car() { }
Car(const Car& copy) { }
virtual ~Car() { }
};

struct Ferrarri : public Car
{
Ferrarri() { }
// conversion ctor: (thats all you need)
Ferrarri(const Car& cvt) : Car(cvt) { }
Ferrarri(const Ferrarri& copy) { }
};

int main()
{
std::list< Car cars(10);
std::list< Ferrarri racingcars(10);
// the following splices Ferraris into Cars
std::copy(racingcars.begin(), racingcars.end(), cars.begin());
// the following constructs (not cast) brand new Ferrarris
std::copy(cars.begin(), cars.end(), racingcars.begin());
}
gu************@gmail.com wrote:
Mr. Salt,

The solution is quite simple to Cars/Ferrarri scenario, but the problem
initially pointed still remains.
How to solve it? The following code is invalid:

void something( std::list<Car>& list_of_cars) {
}
std::list<Ferrarriracingcars(10);
something( racingcars);

That's the error. The dynamic cast will force the runtime to check
inheritance between Ferrari and Cars.

Regards,
Gustavo
That static type check happens without any casting involved. A
container of Ferrarris *is* already a container of Cars.
Now to have something(std::list<>&) work with any Car (Lamborghini,
Carrerra, Aston Martin) - template it:

#include <iostream>
#include <list>

class Car
{
std::string s;
public:
Car(std::string s_ = "Car") : s(s_) { }
const std::string& getstr() const { return s; }
};

class Ferrarri : public Car
{
public:
Ferrarri(const Car& cvt) : Car("Ferrarri") { }
Ferrarri(std::string s_ = "Ferrarri") : Car(s_) { }
};
// something(...) template
template< typename T >
void something( std::list< T >& list_of_cars )
{
typedef typename std::list< T >::iterator TIter;
for( TIter iter = list_of_cars.begin();
iter != list_of_cars.end();
++iter )
{
std::cout << (*iter).getstr();
std::cout << std::endl;
}
}

int main()
{
std::list<Ferrarriracingcars(5);
something( racingcars );
}

/*
Ferrarri
Ferrarri
Ferrarri
Ferrarri
Ferrarri
*/

Consider the implications. That template will work with *any*
derivative of Car - including a derivative not yet written.

Nov 20 '06 #7

Salt_Peter wrote:
That static type check happens without any casting involved. A
container of Ferrarris *is* already a container of Cars.
I think you understand this point because your code did not appear to
take an approach that suggested any misunderstanding, but just in case
of any confusion...

A container of Ferraris *is not* a container of Cars in the
polymorphism sense of "is a". You can not put an Lamborghini in a
container of Ferraris. You can put a Lamborghini in a container of Cars
and that container of Cars might happen to only contain Ferraris before
you put the Lamborghini in. But a container of Cars that happens to
only contain Ferraris is not a container of Ferraris, it is a container
of Cars.

http://www.parashift.com/c++-faq-lit....html#faq-21.3

In fact I don't think this is directly relevant to the questioner, as
the code under discussion uses containers of objects, not containers of
pointers or references, so is presumably not trying to store Cars to be
used polymorphically. However, the phrase "is a" is often strongly
associated with inheritance and polymorphism and I wanted to avoid any
misinterpretation of your statement that a container of Ferraris is a
container of Cars.

Gavin Deane

Nov 21 '06 #8
I'll stop arguing to you because you've been so stubborn to your point
of view.
Your code will allow you to deal with a list of Bananas and not only
Cars.

And semantically speaking, a containter of cars must accept a container
of Ferraris, Porsches, Mercedes, and so on... (but not Apples or
Bananas).

Salt_Peter wrote:
[ Please don't top post ] - rearranged below...
Salt_Peter wrote:
gu************@gmail.com wrote:
I had a similar problem.

There I had my List<template>, and in case of template class were 'Car'
and could not pass a List<Ferrarito my function, just like you're
trying to. I had to make a new function, called "Recast".

In this case, I used an rtti function to dynamically cast it, (checking
if it's safe to cast from Ferrari to Cars, throwing an exception if
they can't be casted). You can cut it off, but bad things can happen if
you cast from, like saying, Cars to Ferraris.

/*!
* This is used to recast the whole list because elements can inherit
each other. Win32 only.
*/
template<class NewElementType>
List<NewElementType>&
Recast() {
// we should be aware if both ElementType and NewElementType are
compatible
ElementType tempT;
NewElementType& tempNT = dynamic_cast<NewElementType&>( tempT); //
force runtime to throw exception if we're casting to wrong datatype

List<NewElementType>* recast = (List<NewElementType>*) this;
return *recast;
}


>
The above invokes undefined behaviour. I can't express to you in words
how dangerous the above code is.
You might think it works in Win32 but in fact it doesn't. Of course, MS
won't tell you that.
Basicly: a recast is dangerous even in the best of conditions - better
a "conversion ctor" which creates a new fully-formed derived object.
And in the event that you are converting a Ferrarri to a car thats done
automatically if the former is derived from the latter( plain copy ctor
invoked). The resulting Cars are spliced Ferraris, of course. Lets
ignore the use of ptrs and polymorphism for now.
>
The solution is so simple and doesn't need a cast of any kind: a
conversion ctor.
>
#include <iostream>
#include <list>
#include <algorithm>
>
struct Car
{
Car() { }
Car(const Car& copy) { }
virtual ~Car() { }
};
>
struct Ferrarri : public Car
{
Ferrarri() { }
// conversion ctor: (thats all you need)
Ferrarri(const Car& cvt) : Car(cvt) { }
Ferrarri(const Ferrarri& copy) { }
};
>
int main()
{
std::list< Car cars(10);
std::list< Ferrarri racingcars(10);
// the following splices Ferraris into Cars
std::copy(racingcars.begin(), racingcars.end(), cars.begin());
// the following constructs (not cast) brand new Ferrarris
std::copy(cars.begin(), cars.end(), racingcars.begin());
}

gu************@gmail.com wrote:
Mr. Salt,

The solution is quite simple to Cars/Ferrarri scenario, but the problem
initially pointed still remains.
How to solve it? The following code is invalid:

void something( std::list<Car>& list_of_cars) {
}
std::list<Ferrarriracingcars(10);
something( racingcars);

That's the error. The dynamic cast will force the runtime to check
inheritance between Ferrari and Cars.

Regards,
Gustavo

That static type check happens without any casting involved. A
container of Ferrarris *is* already a container of Cars.
Now to have something(std::list<>&) work with any Car (Lamborghini,
Carrerra, Aston Martin) - template it:

#include <iostream>
#include <list>

class Car
{
std::string s;
public:
Car(std::string s_ = "Car") : s(s_) { }
const std::string& getstr() const { return s; }
};

class Ferrarri : public Car
{
public:
Ferrarri(const Car& cvt) : Car("Ferrarri") { }
Ferrarri(std::string s_ = "Ferrarri") : Car(s_) { }
};
// something(...) template
template< typename T >
void something( std::list< T >& list_of_cars )
{
typedef typename std::list< T >::iterator TIter;
for( TIter iter = list_of_cars.begin();
iter != list_of_cars.end();
++iter )
{
std::cout << (*iter).getstr();
std::cout << std::endl;
}
}

int main()
{
std::list<Ferrarriracingcars(5);
something( racingcars );
}

/*
Ferrarri
Ferrarri
Ferrarri
Ferrarri
Ferrarri
*/

Consider the implications. That template will work with *any*
derivative of Car - including a derivative not yet written.
Nov 21 '06 #9

gu************@gmail.com wrote:
I'll stop arguing to you because you've been so stubborn to your point
of view.
Your code will allow you to deal with a list of Bananas and not only
Cars.

And semantically speaking, a containter of cars must accept a container
of Ferraris, Porsches, Mercedes, and so on... (but not Apples or
Bananas).
Please don't top post.
Nobody is arguing. And my approach is no better than any other.
However, take note that a container of Cars can store only a mixture of
Car derivatives. It can't hold bananas or trees. Thats not its job, its
not a container of Java objects.
Again, the goal here is to support any car, including a container of
different cars.
>

Salt_Peter wrote:
[ Please don't top post ] - rearranged below...
Salt_Peter wrote:
gu************@gmail.com wrote:
I had a similar problem.
>
There I had my List<template>, and in case of template class were 'Car'
and could not pass a List<Ferrarito my function, just like you're
trying to. I had to make a new function, called "Recast".
>
In this case, I used an rtti function to dynamically cast it, (checking
if it's safe to cast from Ferrari to Cars, throwing an exception if
they can't be casted). You can cut it off, but bad things can happen if
you cast from, like saying, Cars to Ferraris.
>
/*!
* This is used to recast the whole list because elements can inherit
each other. Win32 only.
*/
template<class NewElementType>
List<NewElementType>&
Recast() {
// we should be aware if both ElementType and NewElementType are
compatible
ElementType tempT;
NewElementType& tempNT = dynamic_cast<NewElementType&>( tempT); //
force runtime to throw exception if we're casting to wrong datatype
>
List<NewElementType>* recast = (List<NewElementType>*) this;
return *recast;
}
>
>

The above invokes undefined behaviour. I can't express to you in words
how dangerous the above code is.
You might think it works in Win32 but in fact it doesn't. Of course, MS
won't tell you that.
Basicly: a recast is dangerous even in the best of conditions - better
a "conversion ctor" which creates a new fully-formed derived object.
And in the event that you are converting a Ferrarri to a car thats done
automatically if the former is derived from the latter( plain copy ctor
invoked). The resulting Cars are spliced Ferraris, of course. Lets
ignore the use of ptrs and polymorphism for now.

The solution is so simple and doesn't need a cast of any kind: a
conversion ctor.

#include <iostream>
#include <list>
#include <algorithm>

struct Car
{
Car() { }
Car(const Car& copy) { }
virtual ~Car() { }
};

struct Ferrarri : public Car
{
Ferrarri() { }
// conversion ctor: (thats all you need)
Ferrarri(const Car& cvt) : Car(cvt) { }
Ferrarri(const Ferrarri& copy) { }
};

int main()
{
std::list< Car cars(10);
std::list< Ferrarri racingcars(10);
// the following splices Ferraris into Cars
std::copy(racingcars.begin(), racingcars.end(), cars.begin());
// the following constructs (not cast) brand new Ferrarris
std::copy(cars.begin(), cars.end(), racingcars.begin());
}
gu************@gmail.com wrote:
Mr. Salt,
>
The solution is quite simple to Cars/Ferrarri scenario, but the problem
initially pointed still remains.
How to solve it? The following code is invalid:
>
void something( std::list<Car>& list_of_cars) {
}
std::list<Ferrarriracingcars(10);
something( racingcars);
>
That's the error. The dynamic cast will force the runtime to check
inheritance between Ferrari and Cars.
>
Regards,
Gustavo
>
That static type check happens without any casting involved. A
container of Ferrarris *is* already a container of Cars.
Now to have something(std::list<>&) work with any Car (Lamborghini,
Carrerra, Aston Martin) - template it:

#include <iostream>
#include <list>

class Car
{
std::string s;
public:
Car(std::string s_ = "Car") : s(s_) { }
const std::string& getstr() const { return s; }
};

class Ferrarri : public Car
{
public:
Ferrarri(const Car& cvt) : Car("Ferrarri") { }
Ferrarri(std::string s_ = "Ferrarri") : Car(s_) { }
};
// something(...) template
template< typename T >
void something( std::list< T >& list_of_cars )
{
typedef typename std::list< T >::iterator TIter;
for( TIter iter = list_of_cars.begin();
iter != list_of_cars.end();
++iter )
{
std::cout << (*iter).getstr();
std::cout << std::endl;
}
}

int main()
{
std::list<Ferrarriracingcars(5);
something( racingcars );
}

/*
Ferrarri
Ferrarri
Ferrarri
Ferrarri
Ferrarri
*/

Consider the implications. That template will work with *any*
derivative of Car - including a derivative not yet written.
Nov 21 '06 #10
Salt_Peter wrote:
However, take note that a container of Cars can store only a mixture of
Car derivatives.
Not true. It can only store Cars. C++ standard library containers
are all homogeneous, that is, all their elements of the same type.
A list<Carcannot store a Ferrari.

Of course you could shoe-horn various different objects into
a container by storing their representation, eg. you could have
a list<std::stringand copy all the bytes of the Ferrari into
a string and put it in the list, and then copy them out again
and into a Ferrari structure when you want to get them out of
the list. This appears to be what the OP code is doing, and
is rather poor design to say the least.

Nov 21 '06 #11

Old Wolf wrote:
Salt_Peter wrote:
However, take note that a container of Cars can store only a mixture of
Car derivatives.

Not true. It can only store Cars. C++ standard library containers
are all homogeneous, that is, all their elements of the same type.
A list<Carcannot store a Ferrari.
Says who? If you can store a car, you can store a derivative of it.
To store a Car, i'ld obviously need std::list<Car*and new whatever(),
of course.
Thats probably what you meant.

But note, i'm not storing Cars, i'm passing a *reference* to a
container of Car derivatives.
Add a virtuall foo() to Car and Ferrarri and the something<template
calls Ferrarri::foo() without a hitch. References are polymorphic.
Thats not a hack.
>
Of course you could shoe-horn various different objects into
a container by storing their representation, eg. you could have
a list<std::stringand copy all the bytes of the Ferrari into
a string and put it in the list, and then copy them out again
and into a Ferrari structure when you want to get them out of
the list. This appears to be what the OP code is doing, and
is rather poor design to say the least.
Yes, that i aggree. What specially gets me worked up is seeing
dynamic_casts to convert a base to a child. What the OP could do, as
pointed out, is use a conversion ctor to rebuild the derivative from
base objects - although that is a dubious activity as well, at least
you end up with a valid object.

Nov 22 '06 #12

This discussion thread is closed

Replies have been disabled for this discussion.

By using this site, you agree to our Privacy Policy and Terms of Use.