Given the following code
class T {
public:
virtual ~T () {}
virtual void foo () = 0;
};
class U {
public:
U() {}
~U() {}
void bar () { std::cout << "bar" << std::endl; }
};
class A : public U, public T {
public:
void foo () { std::cout << "foo" << std::endl; }
};
int main () {
A * a = new A;
std::vector<U*> u;
std::vector<T*> t;
u.push_back(a);
t.push_back(reinterpret_cast<T*>(u[0]));
u[0]->bar ();
t[0]->foo ();
delete a;
return 0;
}
I get the output I would expect
bar
foo
However, if I change the definition of U to
class U {
public:
U() {}
virtual ~U() {}
virtual void bar () { std::cout << "bar" << std::endl; }
};
I still compile fine and without warnings/errors but the output is now
bar
bar
What is it about the virtual declaration that prevents me from calling into the foo?
Firstly, there are no virtual base classes in your example. Classes that contain virtual functions are called polymorphic. (There is such thing as "virtual base classes" in C++ but it has nothing to do with your example.)
Secondly, the behavior of your code does not depend on any virtual declarations. You have deliberately destroyed the integrity of the base pointer by using reinterpret_cast. For this reason the behavior of the code is undefined.
A direct cast from one base pointer to another (which is what you are trying to do in your code) is called cross-cast. The only cast in C++ that can carry out a cross-cast is dynamic_cast.
t.push_back(dynamic_cast<T *>(u[0]));
You can perform an indirect cross-cast without dynamic_cast, but for that you have to downcast the pointer to the derived type first (A *) using static_cast and then upconvert it to another base pointer type
t.push_back(static_cast<A *>(u[0])); // upconversion to `T *` is implicit
If you use reinterpret_cast you loose all guarantees, and anything you do is "undefined behaviour". In this case, I expect the VMT got messed up, or the VPTR overwritten.
As an illustration, when I compile the first code above, I get a segfault on execution on my compiler.
If you really want to "cross-execute" you should derive from a common base class, and inherit that base class by U and T virtually ( : virtual public), or use dynamic_cast instead of reinterpret_cast.
Populate t just like you did u:
t.push_back(a);
You don't need reinterpret_cast because A is a T.
Related
I'm trying to figure out why b->boo() actually calls a.far().
is the multiple inheritance from template class and general class forbidden? why does the inherit order matter?
The code is here:
#include <iostream>
template <int somecount>
class inner_parent_class
{
public:
int array[somecount];
virtual void far() = 0;
};
class any_class
{
public:
virtual void boo() = 0;
};
template <int somecount>
class child_class_bad : public inner_parent_class<somecount>, public any_class
{
public:
virtual void boo() override
{
std::cout << "call me" << std::endl;
}
virtual void far() override
{
std::cout << "do not call me" << std::endl;
}
};
template <int somecount>
class child_class_good : public any_class, public inner_parent_class<somecount>
{
public:
virtual void boo() override
{
std::cout << "call me" << std::endl;
}
virtual void far() override
{
std::cout << "do not call me" << std::endl;
}
};
int main()
{
{
child_class_good<32> a;
any_class* b;
auto c = dynamic_cast<void*>(&a);
b = reinterpret_cast<any_class*>(c);
b->boo();
}
{
child_class_bad<32> a;
any_class* b;
auto c = dynamic_cast<void*>(&a);
b = reinterpret_cast<any_class*>(c);
b->boo();
}
return 0;
}
# GCC 9.3.0
# VS 2019 16.5.3
I suppose that both child classes (child_class_good and child_class_bad) are different classes even though their class names are the same, because they are template classes and constructed separately at compiled time. Nevertheless, each class might have its own v-table, so I think calling boo() as their common parent class any_class should correctly work.
reinterpret_cast cannot be used to do what you're trying to do. A reinterpret_cast from a void* to a T* only produces a pointer to a valid T* if the void* pointer it was given was a pointer to an object of type T.
Doing a dynamic_cast<void*>(p) returns a void* which points to the most-derived object pointed to by p. Since your &a is in fact the most-derived object that it points to, it simply converts the pointer to a void*.
Then you perform reinterpret_cast<any_class*> on that void*. The void* points to an object of type child_class_good<32> or child_class_bad<32>. Your cast is saying that the pointer actually points to an any_class. This is incorrect (neither type is standard layout, so the layout of the base classes is not defined), and thus attempting to use the results will yield undefined behavior.
The case that you identify as good is just as invalid as bad; it merely happens to work.
It is not clear why you're trying to do whatever it is you're trying to do, but there's no valid way to take a void* pointing to the most-derived object of an unknown type and casting it to anything useful. In order to use a void*, you have to know the exact type that was used to produce that void*.
class Base {};
class Derived : public Base {};
void func(boost::optional<Base>&) {}
int main () {
boost::optional<Derived> x;
func(x);
}
will func accept both optionals: base and derived?
No, it won't work. func takes an lvalue reference to boost::optional<Base>. That means it can accept an lvalue of type boost::optional<Base>, an lvalue of a type that derives publicly and unambiguously from boost::optional<Base>, or some other type that has an operator boost::optional<Base>&(). None of those is true of boost::optional<Derived>. Class templates are not coviarant in the C++ type system - boost::optional<Derived> does not inherit from boost::optional<Base>.
It would be a different story if func took its argument by value. If it looked like:
void func(boost::optional<Base> ) { }
In that case, you could call func with a boost::optional<Derived>. But that converting constructor is marked explicit, so you would have to write:
func(boost::optional<Base>{x});
It's good that this is explicit - you are marking clear that you are (potentially) slicing x.
Even if it would work (which is likely buy I haven't checked) it would cause slicing. Only Base part would be stored in optional.
optional keeps internally a buffer of the size needed to store Base. And even if Base would be of the same size as Derived (as in your case) still it would store only Base.
EDIT:
Above answer was given for the original question which contained following code:
int main () {
boost::optional x(Derived());
func(x);
}
Such code is not correct because of two reasons:
boost::optional requires template argument
Even with the template argument it would still be function declaration.
I have ignored those issues and assumed that something like this was meant:
int main () {
boost::optional<Base> x = Derived();
func(x);
}
While that code does compile (at least Visual Studio 2013 and Boost 1.60) and causes slicing. As can be seen by running following program:
#include <boost/optional.hpp>
#include <iostream>
class Base
{
public:
virtual ~Base() { std::cout << "~Base" << std::endl; }
};
class Derived : public Base
{
public:
virtual ~Derived() { std::cout << "~Derived" << std::endl; }
};
int main()
{
boost::optional<Base> x = Derived();
}
which produces output
~Derived
~Base
~Base
The second ~Base shows that optional destroyes Base object rather than Derived object. (The ~Derived is from the temporary object Derived() as is the first ~Base.)
I have the following code (stolen from virtual functions and static_cast):
#include <iostream>
class Base
{
public:
virtual void foo() { std::cout << "Base::foo() \n"; }
};
class Derived : public Base
{
public:
virtual void foo() { std::cout << "Derived::foo() \n"; }
};
If I have:
int main()
{
Base base;
Derived& _1 = static_cast<Derived&>(base);
_1.foo();
}
The print-out will be: Base::foo()
However, if I have:
int main()
{
Base * base;
Derived* _1 = static_cast<Derived*>(base);
_1->foo();
}
The print-out will be: Segmentation fault: 11
Honestly, I don't quite understand both. Can somebody explain the complications between static_cast and virtual methods based on the above examples? BTW, what could I do if I want the print-out to be "Derived::foo()"?
A valid static_cast to pointer or reference type does not affect virtual calls at all. Virtual calls are resolved in accordance with the dynamic type of the object. static_cast to pointer or reference does not change the dynamic type of the actual object.
The output you observe in your examples is irrelevant though. The examples are simply broken.
The first one makes an invalid static_cast. You are not allowed to cast Base & to Derived & in situations when the underlying object is not Derived. Any attempt to perform such cast produces undefined behavior.
Here's an example of valid application of static_cast for reference type downcasting
int main()
{
Derived derived;
Base &base = derived;
Derived& _1 = static_cast<Derived&>(base);
_1.foo();
}
In your second example the code is completely broken for reasons that have nothing to do with any casts or virtual calls. The code attempts to manipulate non-initialized pointers - the behavior is undefined.
In your second example, you segfault because you did not instanciate your base pointer. So there is no v-table to call. Try:
Base * base = new Base();
Derived* _1 = static_cast<Derived*>(base);
_1->foo();
This will print Base::foo()
The question makes no sense, as the static_cast will not affect the v-table. However, this makes more sens with non-virtual functions :
class Base
{
public:
void foo() { std::cout << "Base::foo() \n"; }
};
class Derived : public Base
{
public:
void foo() { std::cout << "Derived::foo() \n"; }
};
int main()
{
Base base;
Derived& _1 = static_cast<Derived&>(base);
_1.foo();
}
This one will output Derived::foo(). This is however a very wrong code, and though it compiles, the behavior is undefined.
The whole purpose of virtual functions is that the static type of the variable shouldn't matter. The compiler will look up the actual implementation for the object itself (usually with a vtable pointer hidden within the object). static_cast should have no effect.
In both examples the behavior is undefined. A Base object is not a Derived object, and telling the compiler to pretend that it is doesn't make it one. The way to get the code to print out "Derived::foo()" is to use an object of type Derived.
If I have the following class:
class Foo
{
protected:
int i;
public:
Foo() : i(42) {}
};
Naturally, I don't have access to protected members from the outside, but I can do this little trick: first I create a new class which inherits Foo:
class Foo2 : public Foo
{
public:
int GetI() { return i; }
};
Now, whenever I have an instance of Foo or a pointer to such instance, I can access protected member via casting (since I don't use any additional members):
Foo *f = new Foo();
Foo f2;
std::cout << ((Foo2*)f)->GetI() << std::endl;
std::cout << (reinterpret_cast<Foo2&>(f2)).GetI() << std::endl;
I understand why this works, but will there ever be any bad consequences? Compiler doesn't mind, there aren't any run time checks.
reinterpret_cast<Foo2&>(f2)).GetI()
Technically, this is Undefined behavior. So it might work but it does not have to.
You're down casting a Foo object to a Foo2 object.
A downcast is a cast from a base class to a class derived from the
base class. A downcast is only safe if the object addressed at runtime
is actually addressing a derived class object
To protect your code, you must use dynamic_cast to check a downcast is valid or not.
Using reinterpret_cast is not recommended for down-casting. Use static_cast or dynamic_cast.
Reading chunk of articles, many wrote DO NOT USE DOWN CASTING like you did. One dangerous example is to have a virtual void GetI() in Foo.
EDIT:
In the following code container::push takes an object of type T that derives from base as argument and stores in a vector a pointer to the method bool T::test().
container::call calls each of the stored methods in the context of to the member object p, which has type base, not T. It works as long as the called method does not refer to any member outside base and if test() is not declared virtual.
I know this is ugly and may not be even correct.
How can I accomplish the same thing in a better way?
#include <iostream>
#include <tr1/functional>
#include <vector>
class base {
public:
base(int v) : x(v)
{}
bool test() const { // this is NOT called
return false;
}
protected:
int x;
};
class derived : public base {
public:
bool test() const { // this is called instead
return (x == 42);
}
};
class container {
public:
container() : p(42)
{}
template<typename T>
void push(const T&) {
vec.push_back((bool (base::*)() const) &T::test);
}
void call() {
std::vector<bool (base::*)() const>::iterator i;
for(i = vec.begin(); i != vec.end(); ++i) {
if( (p .* (*i))() ) {
std::cout << "ok\n";
}
}
}
private:
std::vector<bool (base::*)() const> vec;
base p;
};
int main(int argc, char* argv[]) {
container c;
c.push(derived());
c.call();
return 0;
}
What you are doing with your "boost::bind" statement is to call derived::test and pass "b" as a "this" pointer. It's important to remmember that the "this" pointer for derived::test is supposed to be a pointer to a "derived" object - which is not the case for you. It works in your particular situation since you have no vtable and the memory layout is identical - but as soon as that will change, your program will likely break.
And besides, it's just plain wrong - ugly, unreadable, bug-prone code. What are you really trying to do?
[Edit] New answer to the edited question: You should use boost::bind to create a functional closure, that wraps both the object & the member function in a single object - and store that object in your collection. Then when you invoke it, it is always reliable.
If you can't use boost in your application... well, you could do something like boost::bind yourself (just look on how it is done in boost), but it's more likely that you'll get it wrong and have bugs.
To the updated question:
Calling a derived member function on a base object is Undefined Behavior. What you are trying to achieve (code) is wrong. Try to post what you need and people will help with a sensible design.
What you are doing is not correct, and in the simple example it will work, but might just raise hell (one of the possibilities for undefined behavior) in other cases.
Since base::test and derived::test are not virtual, they are two different member methods, so for simplicitly I will call them base::foo and derived::bar. In the binder code you are forcing the compiler into adapting a pointer to bar that is defined in derived as if it was actually defined in base and then calling it. That is, you are calling a method of derived on an object or type base!!! which is undefined behavior.
The reason that it is not dying is that the this pointers in base and derived coincide and that you are only accessing data present in the base class. But it is incorrect.
When you declare base::test virtual, you get the correct behavior: your most derived object in the hierarchy is base, the compiler will use the virtual dispatch mechanism and find out that base is where the final overrider for test is found and executed.
When you declare only derived::test as virtual (and not base) the compiler will try to use an inexistent virtual dispatch mechanism (usually a vtable pointer) in the handed object and that kills the application.
At any rate, all but the virtual base::test uses are incorrect. Depending on what your actual requirements are, the most probably correct way of doing it would be:
class base {
public:
virtual bool test() const;
};
class derived : public base {
public:
virtual bool test() const; // <--- virtual is optional here, but informative
};
int main()
{
derived d; // <--- the actual final type
base & b = d; // <--- optional
if ( std::tr1::bind( &base::test, std::tr1::ref(b))() ) {
// ...
}
}
Note that there is no cast (casts are usually a hint into something weird, potentially dangerous is hiding there), that the object is of the concrete type where you want the method to be called, and that the virtual dispatch mechanism guarantees that even if the
bind is to base::test, as the method is virtual, the final overrider will be executed.
This other example will more likely do funny things (I have not tried it):
struct base {
void foo() {}
};
struct derived : base {
void foo() {
for ( int i = 0; i < 1000; ++i ) {
std::cout << data[i];
}
}
int data[1000];
};
int main() {
base b;
std::tr1::bind((void (base::*)()) &derived::foo, std::tr1::ref(b))();
}