Questions about static_cast - c++

I've wrote a piece of code, but I am confused with its output:
#include <iostream>
using namespace std;
class B{
public:
virtual void foo() {cout << "B::foo" << endl;}
};
class D:public B{
public:
virtual void foo() {cout << "D::foo" << endl;}
void disp() {cout << "D::disp" << endl;}
};
void func(B *pb){
D *pd1 = static_cast<D*>(pb);
pd1->foo();
pd1->disp();
}
int main(int argc, char *argv[])
{
B* pb = new B();
func(pb);
return 0;
}
The output is:
B::foo
D::disp
But as far as I know, pb points to type B. And there's no function named disp() in it? So, why could it get access to disp() function in class D?

Since disp() doesn't access any of the members of the class, it is in principle the same as if it were declared in the global namespace instead of in class, so there are no negative side effects to calling it, even though the instance is not of the right class.
What are you doing is downcasting a pointer of a base class to a pointer of the derived class, even though it was not initialized as such. If disp() tried to access class members that were in D but not in B, you would probably run into segfaults.
Bottom line: don't use static_cast for downcasting unless you're absolutely sure the pointer is actually pointing to an instance of the derived class. If you're unsure, you can use dynamic_cast which fails in the event of mismatch (but there is the overhead of RTTI, so avoid it if you can).
dynamic_cast will return nullptr if the cast is incorrect or throw a std::bad_cast
exception if it casts references, so you will know for sure why it fails instead of possible memory corruption bugs.

The line:
D *pd1 = static_cast<D*>(pb);
Will make the cast regardless if the source pointer is B* or D*. In your case the result will be pointer that points to an object of a wrong type. Method disp will work because it is not using any data member or virtual function of the class D. In more complex case this will lead to unstable behaviour or a crash.
Your objects are polimorphic. You should use the dynamic_cast instead.

What's important in this context, I believe, is that the member function disp() isn't tucked away inside all objects of type D. It's a single function that exists in one place. And whether any object will try to call call disp() is decided by the code.
Your static_cast will produce what the compiler considers a pointer to D regardless of what pointer you pass it. And once you have a pointer to D, the compiler will let you attempt to call disp().
Put another way, static_cast will not protect you from casting a pointer incorrectly.

You did something very bad when you cast a pointer to an object allocated as a B to a pointer to a derived class D. Here's what the standard says, emphasis mine:
5.2.9 Static Cast
If the rvalue of type “pointer to cv1 B” points to a B that is actually a sub-object of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the result of the cast is undefined.
You've invoked undefined behavior by doing that static_cast. The compiler and runtime can do anything and still be compliant when the program invokes undefined behavior.

You need to understand the difference between the various types of C++ casts.
You're using a static cast here, which is the same as saying, "I don't really care if it's actually of that type or not - just try your best".
In this case, you want to know if your pointer is actually of the derived type you're casting it to. You should use a dynamic_cast. This cast will succeed only if the pointer is of the correct type. That means, that if it fails, it will return a NULL pointer.
The behavior you're seeing is what happens when you don't use the right cast for the job, which, while you can try to explain it, is something you really should avoid because it falls in the domain of undefined behavior. In other words, you cannot expect the same side effects across compilers or even different versions of the same compiler. In other words, avoid it.

Related

Can you static_cast "this" to a derived class in a base class constructor then use the result later?

We ran into this scenario in our codebase at my work, and we had a big debate over whether this is valid C++ or not. Here is the simplest code example I could come up with:
template <class T>
class A {
public:
A() { subclass = static_cast<T*>(this); }
virtual void Foo() = 0;
protected:
T* subclass;
};
class C : public A<C> {
public:
C(int i) : i(i) { }
virtual void Foo() { subclass->Bar(); }
void Bar() { std::cout << "i is " << i << std::endl; }
private:
int i;
};
int main() {
C c(5);
c.Foo();
return 0;
}
This code works 100% of the time in practice (as long as the template parameter type matches the subclass type), but if we run it through a runtime analyzer, it tells us that the static_cast is invalid because we're casting this to a C* but the C constructor hasn't run yet. Sure enough, if we change the static_cast to a dynamic_cast, it returns nullptr and this program will fail and crash when accessing i in Bar().
My intuition is that it should always be possible to replace static_cast with dynamic_cast without breaking your code, suggesting that the original code in fact is depending on compiler-specific undefined behavior. However, on cppreference it says:
If the object expression refers or points to is actually a base class subobject of an object of type D, the result refers to the enclosing object of type D.
The question being, is it a base class subobject of an object of type D before the object of type D has finished being constructed? Or is this undefined behavior? My level of C++ rules lawyering is not strong enough to work this out.
In my opinion this is well-defined according to the current wording of the standard: the C object exists at the time of the static_cast, although it is under construction and its lifetime has not yet begun. This would seem to make the static_cast well-defined according to [expr.static.cast]/11, which reads in part:
... If the prvalue of type “pointer to cv1 B” points to a B that is actually a base class subobject of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the behavior is undefined.
It doesn't say that the D object's lifetime must have begun.
We might also want to look at the explicit rule about when it becomes legal to perform an implicit conversion from derived to base, [class.cdtor]/3:
To explicitly or implicitly convert a pointer (a glvalue) referring to an object of class X to a pointer (reference) to a direct or indirect base class B of X, the construction of X and the construction of all of its direct or indirect bases that directly or indirectly derive from B shall have started and the destruction of these classes shall not have completed, otherwise the conversion results in undefined behavior. To form a pointer to (or access the value of) a direct non-static member of an object obj, the construction of obj shall have started and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing the member value) results in undefined behavior.
According to this rule, as soon as the compiler starts constructing the base class A<C>, it is well-defined to implicitly convert from C* to A<C>*. Before that point, it results in UB. The reason for this, basically, has to do with virtual base classes: if the path by which A<C> is inherited by C contains any virtual inheritance, the conversion may rely on data that are set up by one of the constructors in the chain. For a conversion from base to derived, if there is indeed any virtual inheritance on the chain, static_cast will not compile, so we don't really need to ask ourselves the question, but are those data sufficient for going the other way?
I really can't see anything in the text of the standard, nor any rationale, for the static_cast in your example not being well-defined, nor in any other case of static_casting from base to derived when the reverse implicit conversion (or static_cast) would be allowed (excepting the case of virtual inheritance, which as I said before, leads to a compile error anyway).
(Would it be well-defined to do it even earlier? In most cases this won't be possible; how could you possibly attempt to static_cast from B* to D* before the conversion from D* to B* is allowed, without having obtained the B* pointer precisely by doing the latter? If the answer is that you got from D* to B* through an intermediate base class C1 whose constructor has started, but there is another intermediate base class C2 sharing the same B base class subobject and its construction hasn't started yet, then B is a virtual base class, and again, this means the compiler will stop you from then trying to static_cast from B* back down to D*. So I think there are no issues left to resolve here.)

C++ polymorphism different virtual functions can be called by same function name?

#include<iostream>
using namespace std;
class Class1 {
public:
virtual void f() {
cout << "Function f() in Class1\n";
}
};
class Class2 {
public:
virtual void h() {
cout << "Function h() in Class2\n";
}
};
int main() {
Class1 object1, *p;
Class2 object2;
p = &object1;
p = (Class1*)&object2;
p->f();//possibly abnormal program termination. but in fact, it will call function h(),Why?
return 0;
}
The code must be wrong in theory because p->f() there is no function f() in the Class2.
But in fact, the code can be run, and it will call Function h() in the Class2, It's so strange,why??
C++ doesn't have many run-time checks for performance reasons, so it will just do what you tell it to do even if it is illogical.
You are telling it to call the virtual method Class1::f on a pointer organised in the memory layout of Class2 and apparently Class2::h aligns with Class1::f so it gets called.
This is not standardised behaviour and may differ between compilers. See Virtual method table.
There is a problem with the code, and as #tkausi commented, the behavior is undefined.
The problem is that you are using C-style cast which is dangerous and should be avoided in C++. From cppreference:
When the C-style cast expression is encountered, the compiler
attempts to interpret it as the following cast expressions, in this
order:
const_cast<new_type>(expression);
static_cast<new_type>(expression), with extensions: pointer or
reference to a derived class is additionally allowed to be cast to
pointer or reference to unambiguous base class (and vice versa) even
if the base class is inaccessible (that is, this cast ignores the
private inheritance specifier). Same applies to casting pointer to
member to pointer to member of unambiguous non-virtual base;
static_cast (with extensions) followed by const_cast;
reinterpret_cast<new_type>(expression);
reinterpret_cast followed by const_cast.
The first choice that satisfies the requirements of
the respective cast operator is selected, even if it cannot be
compiled (see example). If the cast can be interpreted in more than
one way as static_cast followed by a const_cast, it cannot be
compiled. In addition, C-style cast notation is allowed to cast from,
to, and between pointers to incomplete class type. If both expression
and new_type are pointers to incomplete class types, it's unspecified
whether static_cast or reinterpret_cast gets selected.
Thus, in your case the compiler will select reinterpret_cast which will just reinterpret the raw bytes of your object as something else (and it just happens that the first thing in the virtual table of p points to method h).
To make your program safe, you should instead use static_cast or dynamic_cast:
#include<iostream>
using namespace std;
class Class1 {
public:
virtual void f() {
cout << "Function f() in Class1\n";
}
};
class Class2 {
public:
virtual void h() {
cout << "Function h() in Class2\n";
}
};
int main() {
Class1 object1, *p;
Class2 object2;
p = &object1;
p = static_cast<Class1*>(&object2); // fails to compile
p->f();
return 0;
}
In this case, compilation fails as expected.
Live example: https://godbolt.org/g/noErNr
Note that if we replace static_cast line with p = dynamic_cast<Class1*>(&object2); the code will compile, but p will be set to nullptr at runtime, and trying to call p->f() will result in an error.
The code must be wrong in theory because p->f() there is no function
f() in the Class2.
The code is not only wrong in theory, but it is wrong in pratice too. The thing is that C++ does not hold your hand and does not wrap you in cotton wool, if you do wrong stuff, bad things can happen. Typesafety is your friend, but if you betray it, you are on your own.
In this line:
p = (Class1*)&object2;
you pretend that you could cast a Class2 to a Class1. Anything beyond that is undefined behaviour, which is sloopy speaking a way of saying: c++ does not care what is the output of programs that dont obey the rules.
The way to stay friends with the typesystem is to use static_cast instead of a C-style cast, which would tell you that the cast is not allowed.

Is this a valid downcasting

I have a cpp code where in class c is derived from class b and class b is derived from class a.
Now class b has some public data member. So I am creating a instance of class c on heap passing its pointer to another class as pointer to a and there it is downcasting that pointer to pointer of class b and then printing public variables of class b.
Is this a valid downcasting. I am asking because just change of compiler has broken this working code.
I am including below code snippet which captures problem I am having.
#include <iostream>
using namespace std;
class grand
{
};
class parent : public grand
{
public : parent(){i=0;}
int i;
parent(int j){ i = j;}
void set(int j){i = j;}
};
class child : public parent{
public: child(){};
};
void print ( grand* ptr)
{
parent *p = (parent*) ptr;
std::cout << std::endl << p->i << std::endl;
}
int main() {
// your code goes here
child c;
c.set(9);
print(&c);
return 0;
}
Thanks
Is this a valid downcasting.
Yes. Your cast internally applies static_cast, which, according to §5.2.9/11, will give you the right result. If the argument for ptr doesn't point to a parent, the result of the cast is undefined - and so would the execution of the following code be.
Downcasting of polymorphic types in C++ works via dynamic_cast. Your grand class above isn't polymorphic - you have to add at least a virtual destructor to grand to make it polymorphic. Otherwise you'll get a compiler error with the following code.
parent *p = dynamic_cast<parent*>(ptr); // Once grand is polymorphic...
And check whether the result, p, is non-zero. Only this method reveals (at runtime) whether the cast worked! All others either invoke undefined behavior or undefined, non-zero values.
Some notes:
Downcasting is almost always a sign of bad design. Avoid it if possible, using - for example - virtual (print) functions.
print should take a pointer to const since it doesn't modify any data members.
Your code, as written, is in fact valid, but there are a bunch of observations I'd like to make. Note that it's valid only because the object you pass to print is a parent or further derived class.
Then note that since you have to cast it the print function it's much safer to just change the function signature to take aparent instead of a grand and then you don't have to worry about the casting.
Then note that a likely cause of your problem is that in the file that does the cast, the compiler doesn't see the relationship between grand and parent so your C-style cast falls back to reinterpret_cast which is not what you want. If you can't change the signature of print at least change the cast to static_cast (or possibly dynamic_cast, but you can't do that in your example because the classes aren't polymorphic) so that the compiler will fail to compile when it can't see the class relationship.
Instead of a C-style cast you should apply a dynamic_cast or a at least a static_cast if you compile without RTTI (runtime type information) for some reason.
Your C-style cast is the same as a reinterpret_cast, which essentially interprets the memory pointed to as if an object of type parent would have been constructed there. But, every compiler may have a different memory layout of derived classes, thus that may work in some circumstances but there's no guarantee.

C++ ISO Standard interpretation of dereferencing pointer to base

I would like to know standard's view on dereferencing pointer to base, but I'm not making any progress finding it. Take these two classes for example:
class Base
{
public:
virtual void do_something() = 0;
};
class Derived : public Base
{
public:
virtual void do_something();
};
void foo2(Base *b)
{
Base &b1 = *b; // how this work by standard?
}
void foo()
{
Derived *d = new Derived();
foo2(d); // does this work by standard?
}
So, basically, if pointer of type B to an object of type D is dereferenced, will slicing happen in place, or temporary will emerge? I'm prone to believe that temporary is not an option, because that would mean that temporary is instance of abstract class.
Whatever the truth, I would appreciate any pointers to the ISO standard that says one or the other. (Or third, for that matter. :) )
EDIT:
I threw the point with temporary not being an option as a possible line of reasoning why it behaves the way it does, which is quite logical, but I can't find confirmation in standard, and I'm not a regular reader.
EDIT2:
Through discussion, it became obvious that my question was actually about dereferencing a pointer mechanism, and not about splicing or temporaries. I thank everyone for trying to dumb it down for me, and I finally got answer to the question the puzzled me the most: Why I can't find anything in the standard about this... Obviously it was the wrong question, but I've got the right answer.
Thnx
Base &b = *static_cast<Base *>(d); // does this work by standard?
Yes.
But you can simply do this:
Base &b = *d;
//use b polymorphically!
b.do_something(); //calls Derived::do_something()
No need to use static_cast. After all, Derived is derived from Base.
Reply to your edit:
foo2(d); // does this work by standard?
Yes. Pointer of type Base* can be initialized with pointer of type Derived*.
--
Base &b = *b; // how this work by standard?
No. They're same name. If you mean, Base &b1 = *b, then yes, that works. b1 refers to the object pointed to by b.
Object slicing only occurs when the copy constructor or the assignment operator of the base class gets involved somehow, like in parameter passing by value. You can easily avoid these errors by inheriting from Boost's noncopyable for example, even if only in DEBUG mode.
Neither casting pointers or references nor dereferencing involve any copy construction or assignment. Making a Base reference from a Derived reference is perfectly safe, it's even a standard implicit conversion.
In my C++11 draft, 10 [class.derived] /1 says
[ Note: The scope resolution operator :: (5.1) can be used to refer to
a direct or indirect base member explicitly. This allows access to a
name that has been redeclared in the derived class. A derived class
can itself serve as a base class subject to access control; see 11.2.
A pointer to a derived class can be implicitly converted to a pointer
to an accessible unambiguous base class (4.10). An lvalue of a
derived class type can be bound to a reference to an accessible
unambiguous base class (8.5.3). —end note ]
In most implementations, your foo2 function will store Base& b as a Base*. It obviously can't be a Base itself, because that would be a copy, not a reference. Since it acts (at runtime, not syntactically) like a pointer instead of a copy, there's no splicing concerns.
In your code before your edit, the compiler would know that Base& b was actually d, it would be syntactic sugar, and wouldn't even generate a pointer in the assembly.

dynamic_cast from "void *"

According to this, void* has no RTTI information, therefore casting from void* is not legal and it make sense.
If I remember correctly, dynamic_cast from void* was working on gcc.
Can you please clarify the issue.
dynamic_cast works only on polymorphic types, i.e. classes containing virtual functions.
In gcc you can dynamic_cast to void* but not from:
struct S
{
virtual ~S() {}
};
int main()
{
S* p = new S();
void* v = dynamic_cast<void*>(p);
S* p1 = dynamic_cast<S*>(v); // gives an error
}
In 5.2.7 - Dynamic cast [expr.dynamic.cast] it says that for dynamic_cast<T>(v):
If T is a pointer type, v shall be an rvalue of a pointer to complete class type
If T is a reference type, v shall be an lvalue of a complete class type (thanks usta for commenting on my missing this)
...
Otherwise, v shall be a pointer to or an lvalue of a polymorphic type
So, no, a (void*) value is not allowed.
Let's think about what your request might mean: say you've got a pointer that's really to a Derived1*, but the code dynamic_cast-ing only knows it's a void*. Let's say you're trying to cast it to a Derived2*, where both derived classes have a common base. Superficially, you might think all the pointers would point to the same Base object, which would contain a pointer to the relevant virtual dispatch table and RTTI, so everything could hang together. But, consider that derived classes may have multiple base classes, and therefore the needed Base class sub-object might not be the one to which the Derived* - available only as a void* - is pointing. It wouldn't work. Conclusion: the compiler needs to know these types so it can perform some adjustment to the pointers based on the types involved.
Derived1* -----> [AnotherBase]
[[VDT]Base] <-- but, need a pointer to start of
[extra members] this sub-object for dynamic_cast
(Some answers talk about the need for the pointer you're casting from to be of a polymorphic type, having virtual functions. That's all valid, but a bit misleading. As you can see above, even if the void* is to such a type it still wouldn't work reliably without the full type information, as the real problem is that void* is presumably pointing to the start of the derived object, whereas you need a pointer to the base class sub-object from which the cast-to type derives.)
It is true that void* can't be dynamically_casted from.
You are probably mis-remembering.
With g++ 4.5 and the following code
struct A {
virtual ~A();
};
int main() {
A a;
void *p = &a;
A* pa = dynamic_cast<A*>(p);
}
I get the following error:
cannot dynamic_cast 'p' (of type 'void*') to type 'struct A*' (source is not a pointer to class)
I guess you confuse with dynamic_cast to void*. That is legal and obtains the pointer to the most derived class object.
dynamic_cast from void* is illegal - the type casted from must be polymorphic - contain at least one virtual function (virtual destructor counts too).
To add to Tony's nice answer, this little code snippet helps me for some reason. First, we establish a simple hierarchy. Then, we see if dynamic_cast can "survive" a static_cast. Before this experiment I thought "the run time type information is there, dynamic cast should figure it out." Now I realize "dynamic_cast must have to look up its information based on some tables the compiler is aware of, so it can't have some magical power."
#include <iostream>
#include <cassert>
using namespace std;
class A {
protected:
virtual void foo() { cout << "A" << endl; }
};
class B1 : public A {
private:
virtual void foo() override { cout << "B1" << endl; }
};
class B2 : public A {
public:
virtual void foo() override { cout << "B2" << endl; }
};
int main(int argc, char **argv) {
B1 b1;
// undefined behavior even though dynamic_cast didn't return null
dynamic_cast<B2*>(
static_cast<B2*>(
static_cast<A*>(&b1)))->foo();
// dynamic_cast returns null here though
assert (!dynamic_cast<B2*>
(static_cast<A*>
(static_cast<B2*>
(static_cast<A*>(&b1)))));
}
You can cast a pointer to polymorphic type to void *, but not vice versa.