468,785 Members | 1,668 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

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

Would a static_cast be better style here?

The code shown below is an example from the Coin3D documentation. I believe
the use of the C-style cast is safe under the circumstances, but from what
I've been exposed to (TC++PL(SE)), I would favor using a static_cast. Is
there any technical reason to favor the C-style over a static_cast?

http://doc.coin3d.org/Coin/index.html

void foo(SoNode * node)
{
if (node->getTypeId() == SoFile::getClassTypeId()) {
SoFile * filenode = (SoFile *)node; // safe downward cast, knows the
type
}
else if (node->getTypeId().isOfType(SoGroup::getClassTypeId()) ) {
SoGroup * group = (SoGroup *)node; // safe downward cast, knows the
type
}
}

--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #1
26 2217
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:Xe********************@speakeasy.net...
The code shown below is an example from the Coin3D documentation. I believe the use of the C-style cast is safe under the circumstances, but from what
I've been exposed to (TC++PL(SE)), I would favor using a static_cast. Is
there any technical reason to favor the C-style over a static_cast?

No, if you need a cast, use only the new C++ ones (static_cast,
dynamic_cast, reinterprer_cast). They are there for a reason, to help you
identify potential problems. For example if your code crashes, the first
thing you will do is check the reinterpret_casts at first.


Ioannis Vranos

Jul 22 '05 #2
On Fri, 16 Apr 2004 16:14:17 +0300, Ioannis Vranos wrote:
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:Xe********************@speakeasy.net...

Is there any technical reason to favor the C-style over a static_cast?


No, if you need a cast, use only the new C++ ones (static_cast,
dynamic_cast, reinterprer_cast).


One advantage beeing that you can much more easily search for
static_cast<something>(variable) than (something) variable.

--
NPV

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

Jul 22 '05 #3

"Steven T. Hatton" <su******@setidava.kushan.aa> skrev i en meddelelse
news:Xe********************@speakeasy.net...
The code shown below is an example from the Coin3D documentation. I believe the use of the C-style cast is safe under the circumstances, but from what
I've been exposed to (TC++PL(SE)), I would favor using a static_cast. Is
there any technical reason to favor the C-style over a static_cast?


None whatsoever. Actually, I would advice you never ever use the C-style
cast. The only purpose of it is to be compatible with C.

/Peter
Jul 22 '05 #4
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message news:<Xe********************@speakeasy.net>...
The code shown below is an example from the Coin3D documentation. I believe
the use of the C-style cast is safe under the circumstances, but from what
I've been exposed to (TC++PL(SE)), I would favor using a static_cast. Is
there any technical reason to favor the C-style over a static_cast?


Given the situation, you _probably_ want to use a dynamic_cast instead
of either one. Generally this is a type of situation you want to
avoid though -- except in a few situations like re-creating an object
that's been persisted to a stream of some sort, downcasting tends to
indicate poor design.

Downcasting gives you direct access to the functionality of a derived
class. Generally speaking, the preferred method of doing this is to
wrap that functionality in a virtual functio in the base class so you
can use it without casting down to the derived type.

Contrary to statements elsethread, a C-style cast can do one thing
none of the new casts can. It has nothing to do with the question at
hand, so I won't go into it, but it does exist.
Later,
Jerry.

--
The universe is a figment of its own imagination.
Jul 22 '05 #5
"Jerry Coffin" <jc*****@taeus.com> wrote in message
news:b2*************************@posting.google.co m...
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message news:<Xe********************@speakeasy.net>...
The code shown below is an example from the Coin3D documentation. I believe the use of the C-style cast is safe under the circumstances, but from what I've been exposed to (TC++PL(SE)), I would favor using a static_cast. Is there any technical reason to favor the C-style over a static_cast?


Given the situation, you _probably_ want to use a dynamic_cast instead
of either one. Generally this is a type of situation you want to
avoid though -- except in a few situations like re-creating an object
that's been persisted to a stream of some sort, downcasting tends to
indicate poor design.

Downcasting gives you direct access to the functionality of a derived
class. Generally speaking, the preferred method of doing this is to
wrap that functionality in a virtual functio in the base class so you
can use it without casting down to the derived type.

For downcasts static_cast is better to be used. dynami_cast is for upcasting
and crosscasting.

Contrary to statements elsethread, a C-style cast can do one thing
none of the new casts can. It has nothing to do with the question at
hand, so I won't go into it, but it does exist.

Don't tease our curiosity. Tell it. :-)


Ioannis Vranos

Jul 22 '05 #6
Ioannis Vranos wrote:

For downcasts static_cast is better to be used. dynami_cast is for upcasting
and crosscasting.


"Upcasting" is never necessary, as far as I can tell. dynamic_cast is
used for checked downcasting (e.g., if I cast from Shape to Triangle,
ensures that the Shape really was a Triangle).

-Kevin
--
My email address is valid, but changes periodically.
To contact me please use the address from a recent posting.
Jul 22 '05 #7
"Kevin Goodsell" <us*********************@neverbox.com> wrote in message
news:01*******************@newsread1.news.pas.eart hlink.net...

"Upcasting" is never necessary, as far as I can tell. dynamic_cast is
used for checked downcasting (e.g., if I cast from Shape to Triangle,
ensures that the Shape really was a Triangle).

Yes my silly mistake. Downcasting and crosscasting is dynamic_cast about.
Upcasting needs no casting.



Ioannis Vranos

Jul 22 '05 #8
Ioannis Vranos wrote:
"Kevin Goodsell" <us*********************@neverbox.com> wrote in message
news:01*******************@newsread1.news.pas.eart hlink.net...

"Upcasting" is never necessary, as far as I can tell. dynamic_cast is
used for checked downcasting (e.g., if I cast from Shape to Triangle,
ensures that the Shape really was a Triangle).

Yes my silly mistake. Downcasting and crosscasting is dynamic_cast about.
Upcasting needs no casting.


OK, which way is up? Actually, I didn't even think about that issue. But now
that I think about it. A dynamic_cast would be the thing to use. Upcasting
actually means to cast from a derived to a base class, and _does_, I'm
pretty sure, require a static_cast.

This is a little exercise I made up to try to get a handle on all this.
It's a very tricky topic.
/* Hava Fun */
#include <iostream>
#include <string>
using std::ostream;
using std::string;
using std::cout;

class A{
public:
A(const string& name = "A"):m_name(name)
{}
virtual ostream& toString (ostream& out) const;
friend ostream& operator<<(ostream& out, const A& a);
protected:
string m_name;
};

ostream& A::toString (ostream& out) const{
return out << this->m_name;
}

ostream& operator<<(ostream& out, const A& a)
{
return a.toString(out);
}
class B:public A
{
public:
B(const string& name = "B"):A(name)
{}
ostream& toString (ostream& out) const;

};

ostream& B::toString (ostream& out) const{
A::toString(out);
return out << this->m_name;
}

ostream& operator<<(ostream& out, const B& b)
{
return b.toString(out);
}

int main()
{

A a;
B b;
A* aa_ptr = &a;
A* ab_ptr = &b;
B* bb_ptr = &b;
cout << "A* aa_ptr = &a: " << *aa_ptr << std::endl;
cout << "A* ab_ptr = &b: " << *ab_ptr << std::endl;
cout << "B* bb_ptr = &b: " << *bb_ptr << std::endl;

ab_ptr = static_cast<A*>(&b);
cout<<"ab_ptr = static_cast<A*>(&b): " << *ab_ptr << std::endl;

ab_ptr = dynamic_cast<A*>(&b);

cout << "ab_ptr = dynamic_cast<A*>(&b): " << *ab_ptr << std::endl;

cout << "cout <<(A)*ab_ptr << std::endl;: " <<(A)*ab_ptr << std::endl;

cout << "cout << static_cast<A>(*ab_ptr) << std::endl;: ";
cout <<static_cast<A>(*ab_ptr) << std::endl;

cout << "cout << *dynamic_cast<A*>(ab_ptr) << std::endl;: ";
cout << *dynamic_cast<A*>(ab_ptr) << std::endl;
}

--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #9
Steven T. Hatton wrote:
class A{
public:
A(const string& name = "A"):m_name(name)
{}
virtual ostream& toString (ostream& out) const;
The next line is not necessary. It came from an earlier approach.
friend ostream& operator<<(ostream& out, const A& a);
protected:
string m_name;
};


--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #10
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:AJ********************@speakeasy.net...

OK, which way is up? Actually, I didn't even think about that issue. But now that I think about it. A dynamic_cast would be the thing to use. Upcasting actually means to cast from a derived to a base class, and _does_, I'm
pretty sure, require a static_cast.

No it doesn't, else inheritance would not work properly:
class base
{
// ...
public:
virtual void something() { // .. }
};
class derived1: public base
{
// ...
};

class derived2: public base
{
// ...
};

void some_func(const base *p)
{
p->something();
}

int main()
{
derived 1 d;

some_func(&d);
}
This is a little exercise I made up to try to get a handle on all this.

To get handle of what.

It's a very tricky topic.
/* Hava Fun */
#include <iostream>
#include <string>
using std::ostream;
using std::string;
using std::cout;

class A{
public:
A(const string& name = "A"):m_name(name)
{}
virtual ostream& toString (ostream& out) const;
friend ostream& operator<<(ostream& out, const A& a);
protected:
string m_name;
};

ostream& A::toString (ostream& out) const{
return out << this->m_name;
}

ostream& operator<<(ostream& out, const A& a)
{
return a.toString(out);
}
class B:public A
{
public:
B(const string& name = "B"):A(name)
{}
ostream& toString (ostream& out) const;

};

ostream& B::toString (ostream& out) const{
A::toString(out);
return out << this->m_name;
}

ostream& operator<<(ostream& out, const B& b)
{
return b.toString(out);
}

int main()
{

A a;
B b;
A* aa_ptr = &a;
A* ab_ptr = &b;
B* bb_ptr = &b;
cout << "A* aa_ptr = &a: " << *aa_ptr << std::endl;
cout << "A* ab_ptr = &b: " << *ab_ptr << std::endl;
cout << "B* bb_ptr = &b: " << *bb_ptr << std::endl;

ab_ptr = static_cast<A*>(&b);
cout<<"ab_ptr = static_cast<A*>(&b): " << *ab_ptr << std::endl;

ab_ptr = dynamic_cast<A*>(&b);

cout << "ab_ptr = dynamic_cast<A*>(&b): " << *ab_ptr << std::endl;

cout << "cout <<(A)*ab_ptr << std::endl;: " <<(A)*ab_ptr << std::endl;

cout << "cout << static_cast<A>(*ab_ptr) << std::endl;: ";
cout <<static_cast<A>(*ab_ptr) << std::endl;

cout << "cout << *dynamic_cast<A*>(ab_ptr) << std::endl;: ";
cout << *dynamic_cast<A*>(ab_ptr) << std::endl;
}


I haven't drunk my coffee yet. May be later.



Ioannis Vranos

Jul 22 '05 #11
"Ioannis Vranos" <iv*@guesswh.at.emails.ru> wrote in message
news:c5***********@ulysses.noc.ntua.gr...

Yes my silly mistake. Downcasting and crosscasting is dynamic_cast about.
Upcasting needs no casting.

I took a look at TC++PL to refresh my memory and in summary dynamic_cast is
usually used for downcasts and crosscasts but the type of the object must be
polymorphic, that is to have virtual functions.

static_cast converts between related types, such as one pointer to another
in the same class hierarchy.

reinterpret_cast handles conversions between unrelated types.

dynamic_cast is a form of run-time checked conversion, and is usually used
for downcasts and crosscasts and the type of the object must be
*polymorphic*, that is to have virtual functions.
So if in an hierarchy and you want to perform (compile-time checked)
related- type conversion use static_cast. If you want to check at runtime if
the types are related use dynamic_cast provided that the object is
polymorphic if you want the cast to not indicate failure although it is
correct.
Examples:

#include <iostream>

class A
{
};

class B: public A
{
};

int main()
{
B b;

A *p=&b;
B *bp=dynamic_cast<B *>(p);

std::cout<<bp<<std::endl;
}

Executing: C:\Program Files\ConTEXT\ConExec.exe "C:\MinGW\bin\g++.exe" -std=c++98 -pedantic-errors -O3 -Wall "temp.cpp" -o
temp

temp.cpp: In function `int main()':
temp.cpp:18: error: cannot dynamic_cast `p' (of type `class A*') to type
`class
B*' (source type is not polymorphic) Execution finished.
#include <iostream>

class A
{
public:
virtual void something() const {}
};

class B: public A
{
};

int main()
{
B b;

A *p=&b;
B *bp=dynamic_cast<B *>(p);

std::cout<<bp<<std::endl;
}
Executing: C:\Program Files\ConTEXT\ConExec.exe "C:\MinGW\bin\g++.exe" -std=c++98 -pedantic-errors -O3 -Wall "temp.cpp" -o
temp
Execution finished.


#include <iostream>

class A
{
};

class B: public A
{
};

int main()
{
B b;

A *p=&b;
B *bp=static_cast<B *>(p);

std::cout<<bp<<std::endl;
}
Executing: C:\Program Files\ConTEXT\ConExec.exe "C:\MinGW\bin\g++.exe" -std=c++98 -pedantic-errors -O3 -Wall "temp.cpp" -o
temp
Execution finished.



Ioannis Vranos

Ioannis Vranos

Jul 22 '05 #12
"Ioannis Vranos" <iv*@guesswh.at.emails.ru> wrote in message
news:c5***********@ulysses.noc.ntua.gr...

The same put into shape:

I took a look at TC++PL to refresh my memory and in summary,
static_cast converts between related types, such as one pointer to another
in the same class hierarchy. The conversion is compile-time checked.

reinterpret_cast handles conversions between unrelated types.

dynamic_cast is a form of run-time checked conversion, and the type of the
object must be *polymorphic*, that is to have virtual functions.
So if in an hierarchy and you want to perform (compile-time checked) related
type conversion use static_cast.

If you want to check at runtime if the types are related use dynamic_cast
provided that the object is polymorphic.

If you want to convert between oranges and potatoes use reinterpret_cast.

Examples:

#include <iostream>

class A
{
};

class B: public A
{
};

int main()
{
B b;

A *p=&b;
B *bp=dynamic_cast<B *>(p);

std::cout<<bp<<std::endl;
}

Executing: C:\Program Files\ConTEXT\ConExec.exe "C:\MinGW\bin\g++.exe" -std=c++98 -pedantic-errors -O3 -Wall "temp.cpp" -o
temp

temp.cpp: In function `int main()':
temp.cpp:18: error: cannot dynamic_cast `p' (of type `class A*') to type
`class
B*' (source type is not polymorphic) Execution finished.
#include <iostream>

class A
{
public:
virtual void something() const {}
};

class B: public A
{
};

int main()
{
B b;

A *p=&b;
B *bp=dynamic_cast<B *>(p);

std::cout<<bp<<std::endl;
}
Executing: C:\Program Files\ConTEXT\ConExec.exe "C:\MinGW\bin\g++.exe" -std=c++98 -pedantic-errors -O3 -Wall "temp.cpp" -o
temp
Execution finished.


#include <iostream>

class A
{
};

class B: public A
{
};

int main()
{
B b;

A *p=&b;
B *bp=static_cast<B *>(p);

std::cout<<bp<<std::endl;
}
Executing: C:\Program Files\ConTEXT\ConExec.exe "C:\MinGW\bin\g++.exe" -std=c++98 -pedantic-errors -O3 -Wall "temp.cpp" -o
temp
Execution finished.



Ioannis Vranos

Jul 22 '05 #13
"Ioannis Vranos" <iv*@guesswh.at.emails.ru> wrote in message
news:c5***********@ulysses.noc.ntua.gr...

static_cast converts between related types, such as one pointer to another
in the same class hierarchy. The conversion is compile-time checked.

reinterpret_cast handles conversions between unrelated types.

dynamic_cast is a form of run-time checked conversion, and the type of the
object must be *polymorphic*, that is to have virtual functions.
So if in an hierarchy and you want to perform (compile-time checked) related type conversion use static_cast.

If you want to check at runtime if the types are related use dynamic_cast
provided that the object is polymorphic.

If you want to convert between oranges and potatoes use reinterpret_cast.


And of course to convert from a derived pointer type to a base pointer type
there is no need to cast.


Ioannis Vranos

Jul 22 '05 #14
Ioannis Vranos wrote:
And of course to convert from a derived pointer type to a base pointer
type there is no need to cast.


I believe it depends on what the objective is. If you want to call methods
on the base class instead of on the derived class, I'm pretty sure you need
a static cast to the *object* (not the pointer) when you invoke the
function. If you just want to point to a derived object with a base class
pointer, then you are correct, there is no need to cast.

I haven't tried it yet, but I believe you may also be able to used a scope
resolution operator to directly invoke a baseclass function.
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #15
* "Steven T. Hatton" <su******@setidava.kushan.aa> schriebt:
Ioannis Vranos wrote:
And of course to convert from a derived pointer type to a base pointer
type there is no need to cast.


I believe it depends on what the objective is. If you want to call methods
on the base class instead of on the derived class, I'm pretty sure you need
a static cast to the *object* (not the pointer) when you invoke the
function. If you just want to point to a derived object with a base class
pointer, then you are correct, there is no need to cast.

I haven't tried it yet, but I believe you may also be able to used a scope
resolution operator to directly invoke a baseclass function.


For a virtual function the scope resolution operator is the only way.

A cast won't make any difference for a virtual function.

Btw., the notion that a cast will make a difference for a virtual function is
very common, especially among Java programmers (it doesn't make a difference
in Java either), so you're absolutely not the first one to think so. ;-)

--
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #16
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:hL********************@speakeasy.net...
Ioannis Vranos wrote:
And of course to convert from a derived pointer type to a base pointer
type there is no need to cast.
I believe it depends on what the objective is. If you want to call

methods on the base class instead of on the derived class, I'm pretty sure you need a static cast to the *object* (not the pointer) when you invoke the
function.

You are talking to call base public member functions from the outside?
Because you can do Base::Func() from the inside.

For the outside you can do:
class base
{
public:
void whatever() const {}
};

class derived:public base
{
public:
void whatever() const { /*new definition*/ }
};
derived d;

base *p=&d;

base &r=d;
// They call base::whatever()
p->whatever();
r.whatever();


Ioannis Vranos

Jul 22 '05 #17
Alf P. Steinbach wrote:
* "Steven T. Hatton" <su******@setidava.kushan.aa> schriebt:
If you want to callmethods on the base class instead of on the derived
class, I'm pretty sure you need a static cast to the *object* (not the
pointer) when you invoke the function.
For a virtual function the scope resolution operator is the only way.

A cast won't make any difference for a virtual function.

Btw., the notion that a cast will make a difference for a virtual function
is very common, especially among Java programmers (it doesn't make a
difference in Java either), so you're absolutely not the first one to
think so. ;-)


Read what I wrote very carefuly. I didn't say 'casting the pointer'. Run
this code and look at the last few lines of output. Calling the function on
the _dereferenced_pointer_ without a cast invokes the derived version.
Calling it with a static_cast applied to the object _not_the_pointer_
invokes the base class function.

#include <sstream>
#include <iostream>
#include <string>
using std::ostream;
using std::string;
using std::cout;

class A{
public:
A(const string& name = "A"):m_name(name)
{}
virtual ostream& toString (ostream& out) const;

protected:
string m_name;
};

ostream& A::toString (ostream& out) const{
return out << "Class A.m_name = " << this->m_name << "; ";
}

ostream& operator<<(ostream& out, const A& a)
{
return a.toString(out);
}

class B:public A
{
public:
B(const string& name = "B"):A(name)
{}
ostream& toString (ostream& out) const;

};

ostream& B::toString (ostream& out) const{
A::toString(out);
return out << "Class B.m_name = " << this->m_name << "; ";
}

ostream& operator<<(ostream& out, const B& b)
{
return b.toString(out);
}

int main()
{

A a;
B b;
A* aa_ptr = &a;
A* ab_ptr = &b;
B* bb_ptr = &b;
cout << "A* aa_ptr = &a: " << *aa_ptr << "\n";
cout << "A* ab_ptr = &b: " << *ab_ptr << "\n";
cout << "B* bb_ptr = &b: " << *bb_ptr << "\n\n";

ab_ptr = static_cast<A*>(&b);
cout<<"ab_ptr = static_cast<A*>(&b):\n" << *ab_ptr << "\n\n";

ab_ptr = dynamic_cast<A*>(&b);

cout << "ab_ptr = dynamic_cast<A*>(&b):\n" << *ab_ptr << "\n\n";

cout << "cout << (A)*ab_ptr << \"\\n\";:\n" << (A)*ab_ptr << "\n\n";

cout << "cout << static_cast<A>(*ab_ptr) << \"\\n\";:\n";
cout << static_cast<A>(*ab_ptr) << "\n\n";

cout << "cout << *ab_ptr << \"\\n\";:\n";
cout << *ab_ptr << "\n\n";

cout << "cout << *dynamic_cast<A*>(ab_ptr) << \"\\n\";:\n";
cout << *dynamic_cast<A*>(ab_ptr) << "\n\n";
}
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #18
* "Steven T. Hatton" <su******@setidava.kushan.aa> schriebt:
Alf P. Steinbach wrote:
* "Steven T. Hatton" <su******@setidava.kushan.aa> schriebt:
If you want to callmethods on the base class instead of on the derived
class, I'm pretty sure you need a static cast to the *object* (not the
pointer) when you invoke the function.

For a virtual function the scope resolution operator is the only way.

A cast won't make any difference for a virtual function.

Btw., the notion that a cast will make a difference for a virtual function
is very common, especially among Java programmers (it doesn't make a
difference in Java either), so you're absolutely not the first one to
think so. ;-)


Read what I wrote very carefuly. I didn't say 'casting the pointer'. Run
this code and look at the last few lines of output. Calling the function on
the _dereferenced_pointer_ without a cast invokes the derived version.
Calling it with a static_cast applied to the object _not_the_pointer_
invokes the base class function.


Ah, that is something else, yes. It is a _very_ dangerous and often also very
inefficient thing to do. You're casting an rvalue, yes, an rvalue, and this
is not just a convenient "tell the compiler what type it really is or should
be thought of as", it's an actual conversion of data. It's called a
slice-operation, and it's the same thing as passing a B instance by value
with expected type A, or initializing an A object from a B object. The
resulting value _is_ an A, there's no B part.

You can't do that in Java.

Do note that with a conforming compiler you're then not calling a function on
the original object. For static functions that doesn't make a difference.
But the inefficiency compared to simple qualification and the obfuscation
compared to directly declaring a temporary A means that this is not used.

Summing up: in practice it's meaningless.

Advice: never use it.

--
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #19
Alf P. Steinbach wrote:
* "Steven T. Hatton" <su******@setidava.kushan.aa> schriebt: You can't do that in Java.
There *are* some nice things about Java.
Do note that with a conforming compiler you're then not calling a function
on
the original object. For static functions that doesn't make a difference.
But the inefficiency compared to simple qualification and the obfuscation
compared to directly declaring a temporary A means that this is not used.

Summing up: in practice it's meaningless.

Advice: never use it.


The result of the code listed below was astonishing. Let me know what
results you get:

#include <iostream>
#include <string>
using std::ostream;
using std::string;
using std::cout;

class A{
public:
A(const string& name = "A"):m_name("A0_" + name)
{}
virtual ostream& toString (ostream& out) const;
virtual void setName (const string& name);
protected:
string m_name;
};

ostream& A::toString (ostream& out) const{
return out << "A.m_name = " << this->m_name << "; ";
}

void A::setName (const string& name)
{
this->m_name = "A1_"+name;
}

ostream& operator << (ostream& out, const A& a)
{
return a.toString(out);
}

class B: public A{
public:
B(const string& name = "B"):A(name),m_name("B0_"+name)
{}
virtual ostream& toString (ostream& out) const;
virtual void setName (const string& name);
protected:
string m_name;
};

ostream& B::toString (ostream& out) const{
A::toString(out);
return out << "B.m_name = " << this->m_name << "; ";
}
void B::setName (const string& name)
{
this->m_name = "B1_"+name;
}
ostream& operator<<(ostream& out, const B& b)
{
return b.toString(out);
}

int main()
{
A a;
B b;

A& aref = a;
aref = static_cast<A>(b);

A& abref = b;
abref = static_cast<A>(b);

cout << "aref = " << aref <<"\n";
cout << "abref = " << abref <<"\n";

A ainst = static_cast<A>(b);
cout << "ainst = " << ainst <<"\n";
}
--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #20
"Ioannis Vranos" <iv*@guesswh.at.emails.ru> wrote in message news:<c5***********@ulysses.noc.ntua.gr>...

[ ... ]
For downcasts static_cast is better to be used. dynami_cast is for upcasting
and crosscasting.


It sounds like you've already figured out that this statement was
backwards. It may have already been mentioned, but when casting up a
hierarchy, you don't normally need to use an explicit cast at all.
Contrary to statements elsethread, a C-style cast can do one thing
none of the new casts can. It has nothing to do with the question at
hand, so I won't go into it, but it does exist.

Don't tease our curiosity. Tell it. :-)


One is converting a pointer to a derived object to a pointer to an
inaccessible base. E.g.:

class base1 {};

class base2 {};

class derived : base1, base2 {};

int main() {

derived *d = new derived;

base1 *b1 = (base1 *)d;
base2 *b2 = (base2 *)d;
return 0;
}

There is no combination of static_cast, const_cast or dynamic_cast
that can give the results of C-style casts in this situation.

Since this uses private inheritance, neither an implicit conversion
nor a static_cast is allowed. A const_cast can only add or remove
cv-qualifiers, so it's a non-starter.

You could substitute reinterpret_cast for the C-style casts above, and
the compiler won't complain. The result will be incorrect though. If
you had only a single base class, there's a pretty fair chance that
things would work, even though IIRC you'd officially have undefined
behavior. When you have two (or more) base classes, however, a
reinterpret_cast _can't_ produce correct results. If you used
reinterpret_cast, the conversions to base1* and base2* would
necessarily produce pointers of those types, but with THE SAME
ADDRESS.

Since the two base classes canNOT have the same address, one of them
must be wrong. The C-style cast will actually produce two different
results (i.e. two different addresses), each containing the address of
the correct base subobject.

There are a number of variations on this theme, such as using
references instead of pointers to the objects, or using a
pointer/reference to a member instead of to the whole object.

Now (hopefully) you can see why I didn't really want to get into this:
it's a lot of explanation to cover something that virtually never
matters anyway.
Later,
Jerry.

--
The universe is a figment of its own imagination.
Jul 22 '05 #21
"Jerry Coffin" <jc*****@taeus.com> wrote in message
news:b2*************************@posting.google.co m...
Contrary to statements elsethread, a C-style cast can do one thing
none of the new casts can. It has nothing to do with the question at
hand, so I won't go into it, but it does exist.

Don't tease our curiosity. Tell it. :-)


One is converting a pointer to a derived object to a pointer to an
inaccessible base. E.g.:

class base1 {};

class base2 {};

class derived : base1, base2 {};

int main() {

derived *d = new derived;

base1 *b1 = (base1 *)d;
base2 *b2 = (base2 *)d;
return 0;
}

There is no combination of static_cast, const_cast or dynamic_cast
that can give the results of C-style casts in this situation.

Actually there is
base1 *b1 = static_cast<base1 *>(static_cast<void *>(d));

base2 *b2 = static_cast<base2 *>(static_cast<void *>(d));
The above makes the proper pointer conversion but the above use is an
attempt to defeat the purpose of static_cast (type-relationship checking to
provide some protection).

But in reality we do not perform a casting here but a hack. The inheritance
should not be private in the first place.
So, instead of using C-style casting to do all conversions, C++ provides the
new casting types so as to provide the maximum level of protection and make
it easier to spot the dangerous conversions. For example if your program
crashes somewhere, the first thing you will do is check the
reinterpret_casts since they are the most dangerous ones.
And as i said elsewhere in summary:
static_cast converts between related types, such as one pointer to another
in the same class hierarchy. The conversion is compile-time checked.

reinterpret_cast handles conversions between unrelated types.

dynamic_cast is a form of run-time checked conversion, and the type of the
object must be *polymorphic*, that is to have virtual functions.
So if in an hierarchy and you want to perform (compile-time checked) related
type conversion use static_cast.

If you want to check at runtime if the types are related use dynamic_cast
provided that the object is polymorphic.

If you want to convert between oranges and potatoes use reinterpret_cast.


Ioannis Vranos

Jul 22 '05 #22
Jerry Coffin wrote:
"Ioannis Vranos" <iv*@guesswh.at.emails.ru> wrote in message
news:<c5***********@ulysses.noc.ntua.gr>...
> Contrary to statements elsethread, a C-style cast can do one thing
> none of the new casts can. It has nothing to do with the question at
> hand, so I won't go into it, but it does exist.

Don't tease our curiosity. Tell it. :-)


One is converting a pointer to a derived object to a pointer to an
inaccessible base. E.g.:

There is no combination of static_cast, const_cast or dynamic_cast
that can give the results of C-style casts in this situation. [snip] The C-style cast will actually produce two different
results (i.e. two different addresses), each containing the address of
the correct base subobject.
Is this per the Standard, or just how your/most/some implementations work?
There are a number of variations on this theme, such as using
references instead of pointers to the objects, or using a
pointer/reference to a member instead of to the whole object.

Now (hopefully) you can see why I didn't really want to get into this:
it's a lot of explanation to cover something that virtually never
matters anyway.
Later,
Jerry.


I've actually learned a lot by asking this question. It clarified something
for me in Java as well as a few things in C++. Until now, I had been under
the false impression that casting a Java class to a superclass type would
result in the invocation of a superclass method. I don't know what gave me
that idea. Testing it proved me wrong.

I also tested the following code and found it produces different results in
C++:
b.A::setName("Recast A");
((A)b).setName("C-cast A");//calling A::setName() on a temporary object

--
STH
Hatton's Law: "There is only One inviolable Law"
KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
Mozilla: http://www.mozilla.org
Jul 22 '05 #23
Ioannis Vranos wrote:
"Jerry Coffin" <jc*****@taeus.com> wrote in message
news:b2*************************@posting.google.co m...

One is converting a pointer to a derived object to a pointer to an
inaccessible base. E.g.:

class base1 {};

class base2 {};

class derived : base1, base2 {};

int main() {

derived *d = new derived;

base1 *b1 = (base1 *)d;
base2 *b2 = (base2 *)d;
return 0;
}

There is no combination of static_cast, const_cast or dynamic_cast
that can give the results of C-style casts in this situation.


Actually there is
base1 *b1 = static_cast<base1 *>(static_cast<void *>(d));

base2 *b2 = static_cast<base2 *>(static_cast<void *>(d));
The above makes the proper pointer conversion but the above use is an
attempt to defeat the purpose of static_cast (type-relationship checking to
provide some protection).


I don't know for sure, but I really think the above is equivalent to the
reinterpret_cast version, and not correct for the same reasons.

-Kevin
--
My email address is valid, but changes periodically.
To contact me please use the address from a recent posting.
Jul 22 '05 #24
"Jerry Coffin" <jc*****@taeus.com> wrote in message
news:b2*************************@posting.google.co m...
ADDRESS.

Since the two base classes canNOT have the same address, one of them
must be wrong. The C-style cast will actually produce two different
results (i.e. two different addresses), each containing the address of
the correct base subobject.


Also the code:

#include <iostream>

class base1 {};

class base2 {};

class derived : base1, base2 {};
int main() {

using namespace std;

derived *d = new derived;
//base1 *b1 = static_cast<base1 *>(static_cast<void *>(d));
// base2 *b2 = static_cast<base2 *>(static_cast<void *>(d));

base1 *b1 = (base1 *)d;

base2 *b2 = (base2 *)d;
cout<<"\t"<<b1<<"\t"<<b2<<endl;
return 0;
}

prints the same address. I got a head ache, i 'll check more on this later.


Ioannis Vranos

Jul 22 '05 #25
"Ioannis Vranos" <iv*@guesswh.at.emails.ru> wrote in message
news:c5***********@ulysses.noc.ntua.gr...

prints the same address. I got a head ache, i 'll check more on this

later.
This was due to the empty classes/compiler optimization. So i added an int
member to each. Check this:

#include <iostream>

class base1
{
int x;
};

class base2
{
int x;
};

class derived : base1, base2 {};
int main() {

using namespace std;

derived *d = new derived;
base1 *b1=reinterpret_cast<base1 *>(d);

base2 *b2=reinterpret_cast<base2 *>(reinterpret_cast<unsigned char
*>(d)+sizeof(base1));

/* In simpler steps
unsigned char *p=reinterpret_cast<unsigned char *>(d);

base2 *b2=reinterpret_cast<base2 *>(p+sizeof(base1));
*/
base1 *b3 = (base1 *)d;

base2 *b4 = (base2 *)d;
cout<<"\t"<<b1<<"\t"<<b2<<endl;

cout<<"\t"<<b3<<"\t"<<b4<<endl;

delete d;
return 0;
}


It prints:

C:\c>temp
0x3d2448 0x3d244c
0x3d2448 0x3d244c

C:\c>

So there is a way to do it using the new C++ casts and the behaviour *is*
well defined. True it is an ugly line but this is how a line for doing hack
should look like anyway. And it is a hack not usual operation.


Ioannis Vranos

Jul 22 '05 #26
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message news:<wJ********************@speakeasy.net>...

[ ... ]
The C-style cast will actually produce two different
results (i.e. two different addresses), each containing the address of
the correct base subobject.
Is this per the Standard, or just how your/most/some implementations work?


The part about the addresses being unique takes (IIRC) a concatenation
of about 3 or 4 different sections, but (hopefully) isn't particularly
difficult to believe.

The part about this sort of conversion working with (and only with) a
C-style cast is in 5.4/7.

[ ... ]
I also tested the following code and found it produces different results in
C++:
b.A::setName("Recast A");
((A)b).setName("C-cast A");//calling A::setName() on a temporary object


Yes -- this is the basic difference between a virtual and a
non-virtual function. E.g.:

#include <iostream>

struct base {
void non_virtual_f() { std::cout << "base::non_virtual\n"; }
virtual void virtual_f() { std::cout << "base::virtual\n"; }
};

struct derived : base {
void non_virtual_f() { std::cout << "derived::non_virtual\n"; }
virtual void virtual_f() { std::cout << "derived::virtual\n"; }
};

int main() {
base *b = new derived;

b->non_virtual_f();
b->virtual_f();
return 0;
}

Since we're casting to a visible base class, the conversion from
derived to base can be done implicitly, but the basic effect would be
the same if we cast the address as a pointer to base explicitly. In
any case, when the function isn't virtual, the function that gets
called is determined by the type to which the pointer refers. OTOH,
if the function is virtual, then the function that gets called is
determined by the type of the object being referred TO.

BTW, depending on your compiler, there's a pretty fair chance that
you'll get a warning message if you try to compile this code -- as-is,
base::non_virtual_f is HIDDEN by derived::non_virtual_f, and writing
one function that hides another is typically a mistake (because it
leads to exactly what this code demonstrates -- the function that's
invoked depends on how you refer to the object).
Later,
Jerry.
--
The universe is a figment of its own imagination.
Jul 22 '05 #27

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

7 posts views Thread by buds | last post: by
1 post views Thread by Dave Rahardja | last post: by
11 posts views Thread by Scott Brady Drummonds | last post: by
3 posts views Thread by shrishjain | last post: by
9 posts views Thread by Vincent RICHOMME | last post: by
1 post views Thread by CARIGAR | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.